c#thread无限循环

时间:2014-09-17 22:50:48

标签: c# multithreading join

我正在尝试使用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);

}

2 个答案:

答案 0 :(得分:4)

您需要更改:

custThreads.Add(tt);

在第二个'for'循环中:

tellThreads.Add(tt);

否则你的Join()调用将永远等待doTelling()线程完成,这将永远不会发生,因为将永远不会设置doneFlag。

答案 1 :(得分:1)

将布尔值标记为volatile并不能确保其他线程立即观察到该更改。它只确保如果其他线程观察到更改,它们之后还会观察写入volatile变量的线程在写入之前所做的所有其他写操作。

有关详细信息,请参阅http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx

  

实际上,最后一点是谎言。易失性读写的真正语义比我在此概述的要复杂得多;实际上,它们实际上并不能保证每个处理器都停止正在进行的操作并更新主存储器的缓存。相反,它们提供了关于如何观察读取和写入之前和之后的存储器访问相对于彼此进行排序的较弱保证。某些操作(如创建新线程,输入锁定或使用其中一个Interlocked方法)可以为观察排序提供更强的保证。如果您想了解更多详细信息,请阅读C#4.0规范的第3.10和10.5.3节。

     坦率地说,我不鼓励你做一个不稳定的领域。易失性字段表明你正在做一些彻头彻尾的疯狂:你试图在两个不同的线程上读取和写入相同的值,而不需要锁定。锁定保证锁内部读取或修改的内存一致,锁定保证一次只有一个线程访问给定的内存块,依此类推。

更新: Oleg Mikhaylov注意到,问题中的代码比使用volatile更大的问题。在纠正了这个问题之后,该程序可能会在大多数情况下工作。不过,我在这里留下这个答案,因为使用volatile确实是第二个问题。

我还强烈建议您阅读约瑟夫·阿尔巴哈里的书Threading in C#