Thread.Join()导致死锁 [英] Thread.Join() causing deadlock

查看:801
本文介绍了Thread.Join()导致死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我总共有三个线程.第一个是主UI线程,它启动System.Threading.Thread(ExperimentThread),然后启动BackgroundWorker(WorkerThread).

I have three threads in total. The first is the main UI thread, which starts a System.Threading.Thread (ExperimentThread), which in turn starts a BackgroundWorker (WorkerThread).

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

MainThread and WorkerThread both access a shared resource. I synchronise access to this resource with the following object:

private static readonly Object LockObject = new Object();

在每个线程的主循环中按如下方式使用:

which I use as follows in the main loop of each thread:

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的DoWork方法:

And for completeness here is the DoWork method of WorkerThread:

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.
        }
    }
}

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

This seems to work fine when both threads are running freely.

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

At some point the UI thread will terminate the ExperimentThread by setting one of its boolean fields to true and then wait for it to end, as follows:

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

一旦调用Join(),ExperimentThreadWorkerThread正在访问的共享资源就会发生死锁,并且我的应用程序会无限期挂起.这种情况可能发生10次中的9次.

As soon as Join() is called, a deadlock occurs on the shared resource being accessed by ExperimentThread and WorkerThread, and my application hangs indefinitely. This happens maybe 9 out of 10 times.

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

If I remove ExperimentThread.Join() from the code snippet above, the deadlock never occurs, and ExperimentThread appears to terminate gracefully (it then goes on to terminate WorkerThread by calling CancelAsync()).

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

Any ideas what could be the problem here?

(PS我一直在使用Console.WriteLine()来确定何时获取和释放锁,这使我相信存在死锁.是否有更好的方法来确定这一点,我可能是错的吗?)

(P.S. I've been using Console.WriteLine() to determine when locks are taken and released, which is what has lead me to believe there's a deadlock. Is there a better to determine this, I could be wrong?)

推荐答案

是否有更好的方法来确定这一点,我可能是错的?

Is there a better to determine this, I could be wrong?

一种更好的检查方法是使用并发可视化工具在Visual Studio的更高级别SKU中可用.它将使您确切地看到锁定了每个线程的是什么,以及正在等待线程的是什么,等等.

A better way to check this is to use something like the Concurrency Visualizer available in higher level SKUs of Visual Studio. It will allow you to see exactly what has locked each thread, and what handles threads are waiting on, etc.

由于您陷入僵局的确切原因-没有足够的代码来确定这一点,但是常见的问题是:

As for the exact reason you are getting a deadlock - there isn't enough code to determine this, but common issues are:

  1. ExperimentThread和主线程(带有Join()调用)都锁定在同一对象上,即在lock(LockObject)语句中.
  2. ExperimentThread使用Control.Invoke封送回UI线程的调用.由于UI线程被阻止(在Join()上等待),因此它永远无法处理消息,这将阻止ExperimentThread完成.
  1. ExperimentThread and the main thread (with the Join() call) are both locking on the same object - ie: within a lock(LockObject) statement.
  2. ExperimentThread is using Control.Invoke to marshal a call back onto the UI thread. Since the UI thread is blocked (waiting on the Join()), it can never process messages, which will prevent ExperimentThread from completing.

话虽如此,如果您使用的是.NET 4或更高版本,通常建议使用TaskTask<T>而不是新的Thread. Task提供了一个更好的API用于处理线程,包括允许继续而不是阻塞. C#5对此进行了扩展,甚至允许您异步地等待任务完成.

That being said, in general, I would recommend using Task or Task<T> instead of a new Thread if you're using .NET 4 or higher. Task provides a much nicer API for working with threads, including allowing continuations instead of blocking. C# 5 extends this to even allow you to asynchronously wait for the task to complete.

这篇关于Thread.Join()导致死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆