Thread.Join()导致死锁

我总共有三个主题。 第一个是主UI线程,它启动System.Threading.ThreadExperimentThread ),然后启动BackgroundWorkerWorkerThread )。

MainThreadWorkerThread都访问共享资源。 我使用以下对象同步对此资源的访问:

 private static readonly Object LockObject = new Object(); 

我在每个线程的主循环中使用如下:

 lock (LockObject) { // Do something with shared resource here. } 

ExperimentThread的简化版本如下:

 public void RunExperiment { while (!bStopThread) { lock (LockObject) { // Do something with shared resource here. } if (bStopThread) { break; } else { Application.DoEvents(); Thread.Sleep(250); } } } 

为了完整WorkerThread这里是WorkerThread的DoWork方法:

 private void Worker_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker Worker = sender as BackgroundWorker; for (int X = 0; X < 200; X++) { if (Worker.CancellationPending) { e.Cancel = true; return; } lock (LockObject) { // Do something with shared resource here. } } } 

当两个线程都自由运行时,这似乎工作正常。

在某些时候,UI线程将通过将其一个布尔字段设置为true来终止ExperimentThread ,然后等待它结束,如下所示:

 if (ExperimentThread.IsAlive) { ExperimentThread.StopThread = true; ExperimentThread.Join(); // this line seems to cause the deadlock? } 

一旦调用了Join(), ExperimentThreadWorkerThread访问的共享资源就会出现死锁,我的应用程序将无限期挂起。 这可能发生在10次中的9次。

如果我从上面的代码片段中删除ExperimentThread.Join() ,则永远不会发生死锁,并且ExperimentThread似乎正常终止(然后通过调用CancelAsync()继续终止WorkerThread )。

任何想法可能是什么问题?

(PS我一直在使用Console.WriteLine()来确定何时采取和释放锁定,这使我相信存在死锁。有没有更好的判断,我可能是错的?)

有没有更好的判断,我可能是错的?

检查此问题的更好方法是使用Visual Studio的更高级别SKU中提供的Concurrency Visualizer 。 它将允许您确切地查看已锁定每个线程的内容,以及处理线程正在等待的内容等。

至于你遇到死锁的确切原因 – 没有足够的代码来确定这一点,但常见的问题是:

  1. ExperimentThread和主线程(使用Join()调用)都锁定在同一个对象上 – 即:在一个lock(LockObject)语句中。
  2. ExperimentThread使用Control.Invoke将回调编组回UI线程。 由于UI线程被阻塞(等待Join() ),它永远不会处理消息,这将阻止ExperimentThread完成。

话虽如此,一般来说,如果您使用的是.NET 4或更高版本,我建议使用TaskTask而不是新的ThreadTask为处理线程提供了更好的API,包括允许继续而不是阻塞。 C#5将其扩展为甚至允许您异步等待任务完成。