本文介绍了UI线程中的Thread.Join也阻止了子线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能是一个愚蠢的问题,如果已经在其他地方回答了这个问题,那么我真的很感激,如果有人可以指出我的意思,因为我的搜索没有确定的内容.


简而言之,我的问题是,当我在已标记为停止childThread的子线程上的UI线程中在UI线程中执行childThread.Join()时,它似乎与主线程一样阻塞,因此一切都挂起了. br>目前,由于使用Join导致UI阻塞本身本身就不是问题,因为childThread应该在被告知无论如何退出后都在不到一秒钟的时间内完成.
这是在我等待运行重复进程的线程退出之前发生的,然后我才能运行另一个返回一些信息但不能与另一个进程同时运行的方法.

我的Winforms应用程序通过为硬件添加C API来与USB硬件集成.

硬件API具有一种方法,该方法将启动一个进程,该进程将无限期地反复运行并快速回调新信息,然后我需要将其传递给UI.
可以通过再次调用硬件API来取消此操作,该调用设置了硬件可以看到的标志,使其知道要退出.
我已经用自己的C#代码包装了这个C API,并且在包装器中,我不得不在另一个线程中启动启动过程调用,以使活动不会阻塞UI.

以下是我正在做的事情的编辑摘要.

public class DeviceWrapper
{
    Thread childThread = null;

    void DeviceWrapper
    {
        //Set the callback to be used by the StartGettingInformation() process
        PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
    }

    public void StartProcess()
    {
        childThread = new Thread(new ThreadStart(GetInformationProcess))
        childThread.Start();
    }

    void GetInformationProcess()
    {
        PInvokeMethods.StartGettingInformation();
    }

    //This callback occurs inside the childThread
    void InformationAcquiredCallback(Status status, IntPtr information)
    {
        //This callback is triggered when anything happens in the
        //StartGettingInformation() method, such as when the information
        //is ready to be retrieved, or when the process has been cancelled.
        if(status == Status.InformationAcquired)
        {
            FireUpdateUIEvent();
        }
        //If the cancel flag has been set to true this will be hit.
        else if(status == Status.Cancelled)
        {
            //Reset the cancel flag so the next operation works ok
            PInvokeMethods.SetCancelFlag(false);

            childThread.Abort();
        }
    }

    //This method runs once, and can't run at the same time as GetInformationProcess
    public string GetSpecificInformation()
    {
        //This triggers InformationAcquiredCallback with a status of Cancelled
        StopProcess();

        if(childThread.IsAlive)
        {
            childThread.Join();
        }

        return PInvokeMethods.GetSpecificInformation();
    }

    public void StopProcess()
    {
        PInvokeMethods.SetCancelFlag(true);
    }
}

当我调用childThread.Join()时使用此代码,整个应用程序陷入停顿(我希望UI可以停下来),并且childThread也似乎停顿了,因为回调再也不会被击中了. /p>

但是,如果我改用以下代码:

public string GetSpecificInformation()
{
    //This triggers InformationAcquiredCallback with a status of Cancelled
    StopProcess();
    string s = "";

    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
    {
        if(childThread.IsAlive)
        {
            childThread.Join();
        }
        s = PInvokeMethods.GetSpecificInformation();
    }));

    return s;
}

然后一切都按预期命中,并且childThread确实完成并且一切正常,除了很明显,在WaitCallback触发并分配给我之前,我的字符串返回了空值.

所以,我是否只需要吸收它并更改类,以便使用QueueUserWorkItem和WaitCallback并触发一个事件来处理我的字符串返回?在第一种方法中我正在做一些愚蠢的事情,这也导致childThread也阻塞了吗?
还是考虑到我正在使用的是.NET 3.5,我是否应该完全使用另一种策略或课程?

解决方案

FireUpdateUIEvent();听起来像是一种可能会发送到MsgQueue(Control.Invoke())的方法.当主线程在Join()中等待时,您将遇到经典的死锁.

此外,childThread.Abort()被认为不安全.

我当然会重新设计它.可能可以简化一点.

This may well be a dumb question and if this has already been answered elsewhere then I'd really appreciate it if someone could point me to it as my searching hasn't turned up anything definitive.


In a nutshell, my problem is that when I do childThread.Join() in the UI thread on a child thread which has been flagged to stop the childThread seems to block as well as the main thread so everything just hangs.
That the UI will block due to using Join is not a problem in and of itself at the moment since the childThread should finish in under a second after it's told to quit anyway.
This happens while I'm waiting for a thread running a repeating process to quit before I can run another method which returns some information but can't be run at the same time as the other process.

My Winforms application is integrating with a piece of usb hardware by pinvoking the C API for the hardware.

The hardware API has a method that will start off a process that will run indefinitely and repeatedly and rapidly callback with new information which I then need to pass to the UI.
This operation can be cancelled by another call to the hardware API which sets a flag the hardware can see so it knows to quit.
I've wrapped this C API with my own C# code, and within the wrapper I've had to spin out the start process call in another thread so that the activity doesn't block the UI.

Here are the edited highlights of roughly what I'm doing.

public class DeviceWrapper
{
    Thread childThread = null;

    void DeviceWrapper
    {
        //Set the callback to be used by the StartGettingInformation() process
        PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
    }

    public void StartProcess()
    {
        childThread = new Thread(new ThreadStart(GetInformationProcess))
        childThread.Start();
    }

    void GetInformationProcess()
    {
        PInvokeMethods.StartGettingInformation();
    }

    //This callback occurs inside the childThread
    void InformationAcquiredCallback(Status status, IntPtr information)
    {
        //This callback is triggered when anything happens in the
        //StartGettingInformation() method, such as when the information
        //is ready to be retrieved, or when the process has been cancelled.
        if(status == Status.InformationAcquired)
        {
            FireUpdateUIEvent();
        }
        //If the cancel flag has been set to true this will be hit.
        else if(status == Status.Cancelled)
        {
            //Reset the cancel flag so the next operation works ok
            PInvokeMethods.SetCancelFlag(false);

            childThread.Abort();
        }
    }

    //This method runs once, and can't run at the same time as GetInformationProcess
    public string GetSpecificInformation()
    {
        //This triggers InformationAcquiredCallback with a status of Cancelled
        StopProcess();

        if(childThread.IsAlive)
        {
            childThread.Join();
        }

        return PInvokeMethods.GetSpecificInformation();
    }

    public void StopProcess()
    {
        PInvokeMethods.SetCancelFlag(true);
    }
}

Using this code when I call childThread.Join() the whole application grinds to a halt (which I'd expect for the UI and that's fine) and the childThread also seems to halt because the callback never gets hit again.

However, if I use the following code instead:

public string GetSpecificInformation()
{
    //This triggers InformationAcquiredCallback with a status of Cancelled
    StopProcess();
    string s = "";

    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
    {
        if(childThread.IsAlive)
        {
            childThread.Join();
        }
        s = PInvokeMethods.GetSpecificInformation();
    }));

    return s;
}

Then everything gets hit as expected and childThread does finish and all is well, except obviously my string gets returned empty before the WaitCallback fires and assigns to it.

So, do I just have to suck it up and change the class so that I use the QueueUserWorkItem and WaitCallback and fire an event to deal with my string return?
Is there something daft I'm doing in my first approach that's causing the childThread to block as well?
Or is there another tactic or class entirely that I should be using, bearing in mind it's .NET 3.5 I'm on?

解决方案

Well, FireUpdateUIEvent(); sounds like a method that might Send to the MsgQueue (Control.Invoke()). When the main thread is waiting in a Join() then you have a classic deadlock.

In Addition, childThread.Abort() is not considered safe.

I certainly would re-design it. It probably can be simplified a bit.

这篇关于UI线程中的Thread.Join也阻止了子线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 05:56