C#.NET线程问题

时间:2011-04-02 11:43:58

标签: c# multithreading deadlock thread-synchronization

我面临着C#.NET应用程序中线程之间通信的问题。 希望有人能指导我正确的解决方案。

我在C#.NET中有一个应用程序。它是一个Windows窗体应用程序。 我的应用程序有两个线程 - 一个线程是主线程(UI线程),另一个是子线程。让我们调用子线程“workerThread” 应用程序中只使用了一个表单。让我们将此表单称为“MainForm”

当MainForm加载时启动子线程(使用表单的“Load”事件处理程序启动线程)

在MainForm类中,我有一个名为“stopWork”的变量,它是一个公共布尔变量,它用作一个标志来指示子线程是继续工作还是应该停止

我有另一个类(除了MainForm类),它包含我在子线程中执行的方法。让我们将第二类称为“WorkerClass”。 我将对当前表单(MainForm)的引用传递给“WorkerClass”的构造函数

我在主窗体中有一个“停止”按钮,如果单击它,则将“stopWork”设置为“true”,然后调用“workerThread.Join()”等待子线程完成执行。

在子线程中,方法“doWork”不断检查 for 循环中“parentForm.stopWork”的状态。如果“stopWork”设置为“true”,则循环中断,随后方法结束。

现在,问题是,一旦我点击“停止”按钮,应用程序就会挂起。

我正在粘贴以下代码的部分内容,以便更容易理解:

public partial class MainForm : Form
{
    Thread workerThread = null;
    ThreadStart workerThreadStart = null;
    WorkerClass workerClass = null;

    public bool stopWork = true;

    /*.......... some code ............*/

    private void MainForm_Load(object sender, EventArgs e)
    {
        workerThreadStart = new ThreadStart(startWork);
        workerThread = new Thread(workerThreadStart);
        stopWork = false;
        workerThread.Start();
    }

    private void startWork()
    {
        workerClass = new WorkerClass(this);
    }

    private void buttonStop_Click(object sender, EventArgs e)   //"stop" button
    {
        if (workerThread != null)
        {
            if (workerThread.IsAlive == true)
            {
                stopWork = true;
                workerThread.Join();
            }
        }
    }

    /*.......... some more code ............*/

}

public class WorkerClass
{
    MainForm parentForm=null;

    /*......... some variables and code ........*/

    public WorkerClass(MainForm parentForm)
    {
        this.parentForm=parentForm;
    }

    /* .............. some more code ...........*/

    public void doWork()
    {
       /*.......... some variables and code ...........*/

       for(int i=0;i<100000;i++)
       {
           // ** Here is the check to see if parentForm has set stopWork to true **
           if(parentForm.stopWork==true)
              break;

           /*......... do some work in the loop ..........*/


       }

    }

    /********* and more code .........*/
}

我想我可能知道问题所在。 问题在于子线程中的“doWork”方法试图在父表单中通过调用“workerThread.Join()”方法阻止父表单时访问“stopWork”变量。所以,我认为这是一个“僵局”问题。

我是否正确地发现问题?或者我错了,问题出在其他地方?

如果这确实是一个僵局,解决这个问题的可能解决方案是什么?

我做了一些谷歌搜索,发现了很多关于线程同步的资源以及如何避免死锁。但我无法理解如何将它们专门用于我的问题。

我非常感谢有关解决此问题的任何帮助或指导。

2 个答案:

答案 0 :(得分:3)

是的,您编写的代码高度易受僵局攻击。 BackgroundWorker类特别容易导致这种死锁。

问题出在代码中,我们无法在您的代码段中看到,即WorkerClass。您肯定会以某种方式做一些影响UI的事情,这始终是首先考虑创建线程的主要原因。您可能使用Control.Invoke()在UI线程上运行一些代码并更新控件。也许还表示工作线程已完成,例如,将按钮的Enable属性设置为true。

那是死锁城市,这样的代码在UI线程空闲之前无法运行,回到泵送其消息循环。它永远不会在你的情况下闲置,它被卡在Thread.Join()中。工作线程无法完成,因为UI线程不会空闲,UI线程无法进入空闲状态,因为工作线程未完成。死锁。

BackgroundWorker也存在这个问题,除非UI线程处于空闲状态,否则RunWorkerCompleted事件无法运行。您需要做的是 not 阻止UI线程。说起来容易做起,BGW可以帮助你做到这一点,因为它在完成时会运行一个事件。您可以通过Thread.Join()调用在此代码中执行此事件。你的类中需要一个布尔标志来表示你处于'等待完成'状态。 This answer有相关代码。

答案 1 :(得分:2)

使用BackgroundWorker代替此任务。如果要停止任务的执行,请调用后台工作程序的CancelAsync方法。

一般来说,如果您对多线程没有专家级的理解,那么滚动自己的线程代码(在任何平台上)都会导致灾难(即使这样,它仍然很危险)。