说,我有像这样的静态类
static class PCstatus
{
public static class Cpu
{
//CPU loads
public static int lt;
public static int l1;
public static int l2;
public static int l3;
public static int l4;
//CPU Temp
public static double t0;
//Frequency
}}
我将其用作存储空间(我应该这样做吗?)
我有5-6个线程定期更改此类中的不同变量(注意:没有两个线程更改相同的值),即:
第一个帖子:
PCstatus.lt = 0;,
thread.sleep(1000);
第二
PCstatus.l1 = 0;,
thread.sleep(1000);
然后我有另一个线程定期读取类中的所有值,解析它们并通过串行发送它们。
这是一种理智的方式吗?类中没有锁定机制,因此理论上,其中一个线程可以尝试在最终线程读取时更改var。
我不确定是否会发生这样的事情,我已经运行了这个程序好几天了。到目前为止,还没有注意到任何奇怪的行为。
我可以为类实现一个锁定机制。 (bool _isBeingUsed)并让线程在执行任何操作之前检查该值,但我不确定是否有必要。
我知道从线程输出值的正确方法是使用委托,但如果它不是真的必要,我可以做到没有他们带来的额外复杂性。
答案 0 :(得分:1)
对C#中int
值的读写是原子的,因此您永远不必担心数据剪切。
但是,在类中写入多个值不是原子的,因此在您的示例中:
第一个帖子:
PCstatus.lt = 0;
thread.sleep(1000);
第二
PCstatus.l1 = 0;
thread.sleep(1000);
由于线程3认为lt
为0,因此它也会看到l1
为零,因此无法保证。您可能在此处遇到数据争用问题。
另外,仅仅因为一个线程写入一个变量,它并不意味着其他线程会立即看到它的值。指令的指令重新排序,指令的编译器重新排序和CPU缓存策略可能合谋阻止写入回到主存储器并进入另一个线程。
如果您只是要从一个线程更改单个值,那么请使用Interlocked类上的方法来确保您的更改在线程中可见。它们使用内存屏障来确保对变量的读/写传播跨线程。
如果您要在一次点击中写入多个值,或者如果您想在一次点击中读取多个值,那么您需要使用锁定。
答案 1 :(得分:0)
不需要锁定,但您应该声明这些字段volatile
,以确保其他线程可以立即获取来自一个线程的更新。
请参阅:https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
请注意,您无法将double
声明为volatile
。我认为对于您的应用程序,您可能只需使用float
。否则,您可以使用包含不可变double值的类。
答案 2 :(得分:0)
我有5-6个线程,可以定期更改此类中的不同变量
您可以为每位员工提供事件,而不是为5-6名员工提供单一存储空间。然后,任何需要结果的人都可以订阅它并创建本地存储,这意味着不再有线程问题。
像
这样的东西public static class CPUStats
{
public static EventHandler<CPUEventArgs> Measured;
public static CPUStats()
{
Task.Factory.StartNew(() =>
{
while(true)
{
... // poll CPU data periodically
Measured?.Invoke(null, new CPUEventArgs() { LT = lt, L1 = l1, ... });
}
}, TaskCreationOptions.LongRunning);
}
}
public static class StatsWriter
{
static int lt;
static int l1;
...
public static StatsWriter()
{
CPUStats.Measured += (s, e) =>
{
lt = e.LT;
l1 = e.L1;
}
}
public static void Save()
{
var text = $"{DateTime.Now} CPU[{lt},{l1}...]";
... // save text
}
}