C#.NET线程问题 [英] C#.NET Threading Question

查看:81
本文介绍了C#.NET线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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",则循环中断,然后该方法结束.

现在,问题是,一旦我单击停止"按钮,应用程序就会挂起.

我正在粘贴下面的部分代码,以便于理解:

 公共局部类MainForm:Form{线程workerThread = null;ThreadStart workerThreadStart = null;WorkerClass workerClass = null;public bool stopWork = true;/* ..........一些代码............ */私有void MainForm_Load(对象发送者,EventArgs e){workerThreadStart =新的ThreadStart(startWork);workerThread =新线程(workerThreadStart);stopWork = false;workerThread.Start();}私人无效startWork(){workerClass =新的WorkerClass(this);}private void buttonStop_Click(object sender,EventArgs e)//停止"按钮{如果(workerThread!= null){如果(workerThread.IsAlive == true){stopWork = true;workerThread.Join();}}}/* ..........更多代码............ */}公共阶层WorkerClass{MainForm parentForm = null;/* .........一些变量和代码........ */公共WorkerClass(MainForm parentForm){this.parentForm = parentForm;}/* ..............更多代码........... */公共无效doWork(){/* ..........一些变量和代码........... */for(int i = 0; i <100000; i ++){//**这是检查parentForm是否已将stopWork设置为true **如果(parentForm.stopWork == true)休息;/* .........在循环中做一些工作........ */}}/*********和更多代码......... */} 

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

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

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

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

对于解决此问题的任何帮助或指导,我将不胜感激.

解决方案

是的,您编写的代码高度容易出现死锁.BackgroundWorker类特别容易引起这种死锁.

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

那是死锁之城,此类代码无法运行,直到UI线程空闲,回到泵送其消息循环为止.在您的情况下,它永远不会处于空闲状态,它停留在Thread.Join()中.工作线程无法完成,因为UI线程不会进入空闲状态,UI线程无法进入空闲,因为工作线程尚未完成.死锁.

BackgroundWorker也存在此问题,除非UI线程空闲,否则RunWorkerCompleted事件将无法运行.您需要做的是阻塞UI线程.说起来容易做起来难,BGW可以帮助您正确实现此目标,因为它在事件完成时会运行一个事件.通过Thread.Join()调用,您可以让此事件执行您现在在代码中所做的任何事情.您的班级中需要一个布尔标志,以表明您处于等待完成"状态.此答案具有相关代码.>

I am facing an issue with communication between threads in a C#.NET application. Hope someone will guide me in the right direction about the possible solutions.

I have an application in C#.NET.It is a windows form application. My application has two threads - One thread is the main thread (UI thread) and the other one is the child thread. Lets call the child thread the "workerThread" There is only one form used in the application.Lets call this form the "MainForm"

The child thread is started when the MainForm loads (used the form's "Load" event handler to start the thread)

In the MainForm class, I have a variable named "stopWork" which is a public boolean variable and it serves as a flag to indicate whether the child thread should continue working or should it stop

I have another class (besides the MainForm class) which contains the method that I execute in the the child thread. Lets call this second class the "WorkerClass". I pass a reference to the current form (the MainForm) into the constructor of the "WorkerClass"

I have a button "stop" in the main form which sets "stopWork" to "true" if its clicked and then calls "workerThread.Join()" to wait for the child thread to finish excecution.

In the child thread, the method "doWork" keeps checking the status of "parentForm.stopWork" inside a for loop. If "stopWork" is set to "true" then the loop breaks and subsequently the method ends.

Now, the issue is, once I am clicking the "stop" button ,the application hangs.

I am pasting parts of the code below so that it is easier to understand :

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

I think I may know where the problem lies. The problem is in the "doWork" method in the child thread trying to access "stopWork" variable in the parent form when already the parent form is blocked by calling the "workerThread.Join()" method. So ,I think this is a "deadlock" problem.

Am I right in identifying the problem ? Or am I wrong and the problem lies somewhere else ?

In case this is indeed a deadlock, what are the possible solutions to solve this ?

I did a bit of googling and found lots of resources on thread synchronisation and how to avoid deadlocks. But I could not understand how to apply them specifically to my problem.

I would really appreciate any help or guidance on resolving this issue.

解决方案

Yes, the code you wrote is highly vulnerable to deadlock. The BackgroundWorker class is especially prone to cause this kind of deadlock.

The problem is located in code we can't see in your snippet, the WorkerClass. You are surely doing something there that affects the UI in one way or another, always the primary reason to consider creating a thread in the first place. You probably use Control.Invoke() to have some code run on the UI thread and update a control. Perhaps also to signal that the worker thread is completed and, say, set the Enable property of a button back to true.

That's deadlock city, such code cannot run until the UI thread goes idle, back to pumping its message loop. It will never be idle in your case, it is stuck in Thread.Join(). The worker thread can't complete because the UI thread won't go idle, the UI thread can't go idle because the worker thread isn't finishing. Deadlock.

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.

这篇关于C#.NET线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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