想象一下,我有这样的代码,其中里面的Windows窗体计时器我可以生成一些线程-但我保证只有一个线程使用下面的方法(从答案的一个指示运行位置 -马特·约翰逊):
nb:我们现在假设这种_executing方法有效,我不使用backgroundworker等.
private volatile bool _executing;
private void TimerElapsed(object state)
{
if (_executing)
return;
_executing = true;
if(smth)
{
Thread myThread = new Thread(MainThread1);
myThread.IsBackground = true;
myThread.Start();
}else
{
Thread myThread = new Thread(MainThread2);
myThread.IsBackground = true;
myThread.Start();
}
}
public void MainThread1()
{
try
{
methodWhichAddelementTomyList(); // e.g., inside list.add();
}
finally
{_executing = false;}
}
public void MainThread2()
{
try
{
methodWhichAddelementTomyList(); // e.g., inside list.add();
}
finally
{_executing = false;}
}
Run Code Online (Sandbox Code Playgroud)
现在我也有List实例变量,你可以看到我从访问MainThread1和MainThread2-但因为我的逻辑上面我确保MainThread1并MainThread2从未在并行运行,我还是要做出list volatile?我是否可以遇到与缓存列表变量相关的问题?
编辑:这种方法是否也保护我不会并行运行这些线程?(链接问题中的答案有点不同 - 它运行计时器内的工作 - 所以我想仔细检查).
EDIT2:老实说,下面是否应该volatile在我的list对象上应用关键字没有共同意见.这种状况让我很困惑.如此记录的答案仍然受到欢迎; 否则这还没有完全回答
这里似乎有两个问题:
\n\n如果您使用两个线程,但它们从不异步运行,那么为什么要使用两个线程呢?只需适当地序列化您的方法,即坚持一个线程。
但是,如果需要两个线程(例如,允许一个线程继续处理/保持不受阻塞,而另一个线程正在执行某些其他任务):即使您已对此进行编码以确保没有两个线程可以同时访问该列表,为了安全起见,我会添加一个锁定结构,因为列表不是线程安全的。对我来说,这是最简单的。
您可以使用线程安全集合来代替,例如System.Collections.Concurrent中的集合之一。否则,您需要同步对列表的所有访问(即:将每个添加调用放在锁中),
\n\n我个人避免使用 volatile。Albahari对此有一个很好的解释:“易失性关键字确保字段中始终存在最新值。这是不正确的,因为正如我们\xe2\x80\x99所看到的,写入后跟可以重新排序读取。”
\n\n易失性只是确保两个线程同时看到相同的数据。它根本不会阻止它们交错读取和写入操作。
\n\n例如:\n声明一个同步对象,例如:
\n\nprivate static Object _objectLock = new Object();\nRun Code Online (Sandbox Code Playgroud)\n\nmethodWhichAddelementTomyList并在您的方法(以及修改列表的其他任何地方)中使用类似的方法,以确保从不同线程对资源进行串行访问:
lock(_objectLock)\n{\n list.Add(object);\n}\nRun Code Online (Sandbox Code Playgroud)\n