线程.加入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,我是否应该完全使用另一种策略或类?
好吧,FireUpdateUIEvent();
听起来像是一个Post发送到MsgQueue(Control.Invoke()
)的方法。当主线程在Join()
中等待时,就会出现典型的死锁。
此外,childThread.Abort()
不被认为是安全的。
那么,我是否只需要接受它并更改类,以便使用QueueUserWorkItem和WaitCallback并触发一个事件来处理字符串返回?
我当然会重新设计它。它可能会简化一点。