我目前正在WinForm C#中开发一个应用程序以显示设备中的值,但是我需要找到正确的方法。
我在Mainform
构造函数中启动了一个无限循环的任务。此任务是从设备读取数据并将其写入共享变量。
Mainform
正在读取这些共享变量以显示数据。
由于任务仅在写入而Mainform
仅在读取共享变量,我需要对共享变量使用锁定指令吗?
如果不使用Lock,会有什么风险?
下面是Mainform
构造函数中任务的开始。
谢谢!
Task.Run(() =>
{
while (true)
{
try
{
ReadDeviceData();
}
catch (Exception e)
{
Dispatcher.CurrentDispatcher.Invoke(() =>
MessageBox.Show(e.Message +"\n\n"+ e.StackTrace, "task exception\n"));
}
Thread.Sleep(200);
}
});
答案 0 :(得分:0)
如果只有一个线程写入变量,那么您不必锁定。同时尝试写入一个变量时,建议使用锁。
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
答案 1 :(得分:0)
这取决于ReadDeviceData
。
在C#的内存模型中,读取int
,bool
或object('s reference)
是安全的。
在其他情况下,您可以考虑使用ReaderWriterLock
或ReaderWriterLock
,这更适合您的情况。
答案 2 :(得分:0)
lock
关键字不会锁定变量。它定义了一部分代码,一次只能在一个线程上执行。例如,在这两个代码块中,任何时刻都只能执行一个,并且只能在一个线程上执行:
lock (lockObject)
{
this.A = random.Next();
this.B = random.Next();
this.C = this.A + this.B;
}
lock (lockObject)
{
Console.WriteLine("{0}+{1}={2}", this.A, this.B, this.C);
}
因此,在任何给定时刻,只有一个线程正在读取或写入成员变量A,B和C。
如果我们卸下锁,会发生什么?操作系统使用抢占式多线程,因此您不能确保在任何两行代码之间(有时甚至在执行过程中)任何时候都不会中断您的代码。因此,例如,第二个代码块可能出现在第一个代码块中的任何两行之间。让我们看看...
this.A = random.Next();
this.B = random.Next();
Console.WriteLine("{0}+{1}={2}", this.A, this.B, this.C);
this.C = this.A + this.B;
您可以清楚地看到,该程序在数学上会很糟糕。
话虽如此,我们通过巧妙地分配事物,可以毫无问题地缓解问题。
var results = new SomeClass
{
A = random.Next(),
B = random.Next()
};
results.C = results.A + results.B;
this.LatestResults = results;
现在,唯一共享的变量(因为每个线程都有自己的局部变量)是LatestResults
。可以通过单个原子操作进行更新。在这种情况下,不需要锁定。
答案 3 :(得分:0)
除非您是无锁多线程编程的专家,否则在阅读和时应始终锁定,除非您不问这个问题。不带锁的线程有很多警告,所以最好不要后悔。
请记住,毫无争议的锁很便宜。您可以在一秒钟内锁定一百万次,而您的CPU甚至不会注意到。争执时锁成为瓶颈。如果您的UI偶尔访问共享数据,而不是处于紧密循环中,则使用锁应该没有问题。在这种情况下,没有理由寻找无锁解决方案。