c#线程无限循环

c#线程无限循环,c#,multithreading,join,C#,Multithreading,Join,我正在尝试使用AutoResetEvent运行两组线程以相互协调; 在第一组(客户)完成后,我使用thread.join()确保第一组中的所有线程都完成,设置标志以停止第二个线程。但是,thread.join()从未完成,调试器在其间失去了跟踪。旗帜从未设置,因此它一直在运行。 有人能看看这里出了什么问题吗?谢谢 private static AutoResetEvent tellerFree = new AutoResetEvent(true); private volatile static

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

}
private static AutoResetEvent tellfree=新的AutoResetEvent(true);
私有易失性静态bool doneflag=true;
公共静态void runMultTeller()
{
List custThreads=新列表();
List=newlist();

for(int i=1;i将布尔值标记为
volatile
并不确保其他线程立即观察到该更改。它只确保如果其他线程观察到该更改,则它们随后也会观察在写入volatile变量之前写入该变量的线程所执行的所有其他写入操作

有关更多信息,请参阅:

实际上,最后一点是谎言。易失性读写的真正语义比我在这里概述的要复杂得多;事实上,它们并不能保证每个处理器停止它正在做的事情,并更新主内存中的缓存。相反,它们对读之前和之后的内存访问方式提供了较弱的保证可以观察到s和写操作是相对于彼此排序的。某些操作,如创建新线程、输入锁或使用联锁方法系列中的一种,可以更有力地保证对排序的观察。如果您想了解更多详细信息,请阅读C#4.0规范的第3.10节和第10.5.3节

坦率地说,我不鼓励您创建易失性字段。易失性字段是您正在做一些完全疯狂的事情的标志:您正在尝试在两个不同的线程上读写相同的值,而无需设置锁。锁保证在锁内读取或修改的内存是一致的,锁guaran一次只有一个线程访问给定的大块内存,以此类推

更新: 正如Oleg Mikhaylov所注意到的那样,问题中的代码比仅仅使用
volatile
有更大的问题。在纠正了这个问题之后,程序可能大部分时间都会工作。不过,我把这个答案留在这里,因为
volatile
的使用确实是第二个问题


我还强烈建议您阅读Joseph Albahari的书。

将布尔值标记为
volatile
并不能确保其他线程立即观察到该更改。它只能确保如果其他线程观察到该更改,它们随后也会观察到编写volatir的线程执行的所有其他写入操作在写入变量之前先对其进行初始化

有关更多信息,请参阅:

实际上,最后一点是谎言。易失性读写的真正语义比我在这里概述的要复杂得多;事实上,它们并不能保证每个处理器停止它正在做的事情,并更新主内存中的缓存。相反,它们对读之前和之后的内存访问方式提供了较弱的保证可以观察到s和写操作是相对于彼此排序的。某些操作,如创建新线程、输入锁或使用联锁方法系列中的一种,可以更有力地保证对排序的观察。如果您想了解更多详细信息,请阅读C#4.0规范的第3.10节和第10.5.3节

坦率地说,我不鼓励您创建易失性字段。易失性字段是您正在做一些完全疯狂的事情的标志:您正在尝试在两个不同的线程上读写相同的值,而无需设置锁。锁保证在锁内读取或修改的内存是一致的,锁guaran一次只有一个线程访问给定的大块内存,以此类推

更新: 正如Oleg Mikhaylov所注意到的那样,问题中的代码比仅仅使用
volatile
有更大的问题。在纠正了这个问题之后,程序可能大部分时间都会工作。不过,我把这个答案留在这里,因为
volatile
的使用确实是第二个问题

我还强烈建议您阅读Joseph Albahari的书。

您需要更改:

custThreads.Add(tt);
在第二个“for”循环中:

tellThreads.Add(tt);
否则,Join()调用将永远等待doTelling()线程完成,这将永远不会发生,因为doneFlag将永远不会被设置。

您需要更改:

custThreads.Add(tt);
在第二个“for”循环中:

tellThreads.Add(tt);

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

您不需要为此设置信号量吗?如果您正在处理这些线程之间的生产者/消费者关系,我建议通读一遍。我不确定这是否是您有意为之,但按照您现在设置的方式,所有这些线程都有可能发生一个生产线程可以释放50个消费线程。我可以想象,您希望一个线程生产的每个项目恰好被一个消费线程消费。如果不是,那么我很抱歉。感谢您指出。在这个示例中,我没有尝试这样做。也许下次吧。您不需要一个信号灯吗?如果您正在处理一个生产线程/消费线程r这些线程之间的关系,我建议通读一遍。我不确定这是否是您有意的,但按照您现在设置的方式,所有50个消费线程都有可能被一个生产线程释放。我可以想象,您希望一个线程生成的每个项目都被一个消费线程消费ead。如果没有,那么我道歉。谢谢你指出。我在这个示例中没有尝试这样做。也许下次吧。@EdS。不,没有。州政府