2

我面临 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”方法试图访问父表单中的“stopWork”变量,而父表单已经通过调用“workerThread.Join()”方法被阻止。所以,我认为这是一个“死锁”问题。

我确定问题是否正确?还是我错了,问题出在其他地方?

如果这确实是一个死锁,有什么可能的解决方案来解决这个问题?

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

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

4

2 回答 2

3

是的,您编写的代码极易出现死锁。BackgroundWorker 类特别容易导致这种死锁。

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

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

BackgroundWorker has this problem too, the RunWorkerCompleted event cannot run unless the UI thread is idle. What you need to do is not block the UI thread. Easier said than done, BGW can help you get this right because it runs an event when it completes. You can have this event do whatever you now do in the code past the Thread.Join() call. You'll need a boolean flag in your class to indicate that you are in the 'waiting for completion' state. This answer has relevant code.

于 2011-04-02T14:38:09.313 回答
2

请改用BackgroundWorker来完成此任务。当你想停止任务的执行时,调用后台工作者的CancelAsync方法。

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

于 2011-04-02T11:53:25.630 回答