线程.加入UI线程也会阻塞子线程

本文关键字:线程 加入 UI | 更新日期: 2023-09-27 18:29:48

这可能是一个愚蠢的问题,如果这个问题已经在其他地方得到了答案,那么如果有人能给我指一下,我将不胜感激,因为我的搜索还没有找到任何明确的结果。


简而言之,我的问题是,当我在一个子线程上的UI线程中执行childThread.Join()时,该子线程似乎和主线程一样阻塞,所以一切都挂起了
UI会因为使用Join而被阻塞,这本身并不是问题,因为childThread应该在被告知退出后不到一秒钟内完成
这种情况发生在我等待运行重复进程的线程退出时,然后我才能运行另一个方法,该方法返回一些信息,但不能与其他进程同时运行。

我的Winforms应用程序正在与一块usb硬件集成,方法是为硬件插入C API。

硬件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似乎也会停止,因为回调永远不会再次命中。

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

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,我是否应该完全使用另一种策略或类?

线程.加入UI线程也会阻塞子线程

好吧,FireUpdateUIEvent();听起来像是一个Post发送到MsgQueue(Control.Invoke())的方法。当主线程在Join()中等待时,就会出现典型的死锁。

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

那么,我是否只需要接受它并更改类,以便使用QueueUserWorkItem和WaitCallback并触发一个事件来处理字符串返回?

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