这可能是一个愚蠢的问题,如果这个问题已经在别处得到解答,那么如果有人能指出我的答案,我将不胜感激,因为我的搜索没有找到任何确定的答案。
简而言之,我的问题是,当我在已标记为停止的子线程上的 UI 线程中执行 childThread.Join() 时,childThread 似乎与主线程一样阻塞,因此一切都挂起。< br/>
由于使用 Join 而导致 UI 阻塞目前本身并不是问题,因为 childThread 应该在被告知退出后不到一秒内完成。
在我等待运行重复进程的线程退出之前,我可以运行另一个返回一些信息但不能与另一个进程同时运行的方法时,会发生这种情况。
我的 Winforms 应用程序通过调用硬件的 C API 与一个 USB 硬件集成。
硬件 API 有一个方法可以启动一个进程,该进程将无限期地重复运行并使用新信息快速回调,然后我需要将这些信息传递给 UI。
可以通过对硬件 API 的另一个调用来取消此操作,该 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()
不被认为是安全的。
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?
我当然会重新设计它。它可能可以简化一点。
关于c# - Thread.Join 在 UI 线程中也阻塞子线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9997019/