c线程无限循环
本文关键字:无限循环 线程 | 更新日期: 2023-09-27 18:22:30
我正在尝试使用AutoResetEvent
运行两组线程以相互协调;第一组(客户)完成后,我使用thread.join()
来确保第一组中的所有线程都完成了,并设置了停止第二个线程的标志。然而,thread.join()
从未完成,调试器在两者之间失去了跟踪。这面旗帜从未立过,所以它一直在运行。有人能看看这里出了什么问题吗?谢谢
private static AutoResetEvent tellerFree = new AutoResetEvent(true);
private volatile static bool doneflag = true;
public static void runMultTeller()
{
List<Thread> custThreads = new List<Thread>();
List<Thread> tellThreads = new List<Thread>();
for (int i = 1; i <= 50; i++)
{
Thread td = new Thread(getTeller);
td.Name = Convert.ToString(i);
custThreads.Add(td);
td.Start();
}
for (int j = 1; j <= 5; j++)
{
Thread tt = new Thread(doTelling);
tt.Name = Convert.ToString(j);
custThreads.Add(tt);
tt.Start();
}
foreach (Thread tc in custThreads)
{
if (tc.IsAlive)
{
tc.Join();
}
}
Console.WriteLine("Customer are done");
doneflag = false;
foreach (Thread t2 in tellThreads)
{
t2.Join();
}
Console.WriteLine("Teller are done");
Console.WriteLine("Done");
Thread.Sleep(5000);
}
static public void doTelling()
{
string name = Thread.CurrentThread.Name;
while (doneflag)
{
Console.WriteLine("teller#{0} serving", name);
Thread.Sleep(500);
Console.WriteLine("teller#{0} done", name);
tellerFree.Set();
}
}
static public void getTeller()
{
string name = Thread.CurrentThread.Name;
Console.WriteLine("customer#{0} Enter", name);
tellerFree.WaitOne();
Console.WriteLine("customer#{0} Leave", name);
}
您需要更改:
custThreads.Add(tt);
在第二个"for"循环中:
tellThreads.Add(tt);
否则,Join()调用将永远等待doTelling()线程完成,这将永远不会发生,因为doneFlag永远不会设置。
将布尔值标记为volatile
并不能确保其他线程立即观察到这种变化。它只确保如果其他线程观察到更改,它们随后也会观察到写入volatile变量的线程在写入它之前所做的所有其他写入。
请参阅http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx更多信息:
事实上,最后一点是谎言。volatile读写的真正语义比我在这里概述的要复杂得多;事实上,它们实际上并不能保证每个处理器都停止它正在做的事情,并从主存中更新缓存。相反,它们提供了较弱的保证,即在读写之前和之后的存储器访问可以如何被观察到相对于彼此是有序的。某些操作,如创建新线程、输入锁或使用Interlocked系列方法中的一个,会为观察排序提供更强的保证。如果您需要更多详细信息,请阅读C#4.0规范的3.10和10.5.3节。
坦率地说,我不鼓励你做一个不稳定的领域。易失性字段表明你正在做一些疯狂的事情:你试图在两个不同的线程上读写相同的值,而不加锁。锁保证在锁内读取或修改的内存是一致的,锁保证一次只有一个线程访问给定的内存块,等等
更新:正如Oleg Mikhaylov所注意到的,问题中的代码有一个比仅使用volatile
更大的问题。在纠正了这个问题之后,这个程序可能大部分时间都能工作。尽管如此,我还是把这个答案留在这里,因为volatile
的使用确实是第二个问题。
我还强烈建议您阅读Joseph Albahari的《C#线程》一书。