c# - UI线程阻止DLL线程运行
问题描述
我有一个调用 C DLL 的 C# 应用程序。DLL 使用 CreateThread(...,THREAD_PRIORITY_TIME_CRITICAL) 创建一个时间关键的线程。DLL 被传递给回调的委托,以通知应用程序的通信状态。在 UI 开始运行之前一切正常,例如鼠标单击事件处理程序。只要 UI 事件处理程序正在运行,DLL 线程就会停止并仅在事件处理程序退出后恢复。代码摘录如下。
调用 SetCallback() 将回调函数设置为 DllSetStatus(),它将一些值打印到 RichTextBox "criticalRtb"
DllSetStatus() 可以从 DLL 线程调用或响应来自 C# 应用程序的调用(即 PrintToRTB() 可以从 DLL 线程调用或响应对 DLL_GetStatus() 的调用,如下所示)
一旦进入任何托管代码事件处理程序,如果 DllSetStatus() 正在从 DLL 线程执行,它将停止执行,直到 UI 线程退出。
有没有办法让 DLL 线程在 UI 中继续执行?
我尝试过的事情:
将 UI 线程优先级设置为最低
在事件处理程序中插入 Thread.Sleep()
public delegate void statusDelegate(int status); [DllImport(@"CommDLL.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern int DLL_SetCallback(statusDelegate fPtr); static statusDelegate setStatusDeleg; static object rtfLockObj= new object(); private static bool SetCallback() { setStatusDeleg = DllSetStatus; try { return (DLL_SetCallback(setStatusDeleg) == 0 ? true : false); } catch (Exception e) { dllError(e); return false; } } public static void DllSetStatus(int status) { if (Monitor.TryEnter(rtfLockObj, -1)) { try { SafeRtbWrite(status); } finally { Monitor.Exit(rtfLockObj); } } } private delegate void SafeWriteDelegate(int status); public static void SafeRtbWrite(int status) { if (criticalRtb.InvokeRequired) { var deleg = new SafeWriteDelegate(SafeRtbWrite); criticalRtb.Invoke(deleg, new object[] { status }); } else { int selStart = criticalRtb.TextLength; criticalRtb.DeselectAll(); criticalRtb.AppendText("Status: " + status); criticalRtb.Select(selStart, criticalRtb.TextLength - selStart); criticalRtb.SelectionColor = Color.DarkRed; criticalRtb.DeselectAll(); } }
DLL代码如下:
typedef void(__stdcall * CsSetStatusFunc)(int);
CsSetStatusFunc PrintToRTB = (CsSetStatusFunc)0;
DllExport int __cdecl DLL_SetCallback(CsSetStatusFunc funcPtr)
{
PrintToRTB = funcPtr;
return(0);
}
DllExport int __cdecl DLL_GetStatus(void)
{
PrintToRTB(currStatus);
return(0);
}
static DWORD WINAPI threadComm(void* param)
{
(void)param;
for (;;)
{
portRead();
if (currStatus != lastStatus)
{
PrintToRTB(currStatus);
lastStatus = currStatus;
}
Sleep(0);
}
return(0);
}
解决方案
由于调用 Invoke,似乎在 App 消息队列中发布消息的 DLL 回调被 UI 事件产生的任何 UI 消息阻止,因此如果在任何 UI 事件消息之后发布 Invoke 消息,它将不会执行直到首先处理 UI 事件。如果 Invoke 消息处于挂起状态,我目前正在使用 DoEvents() 来使用队列中的消息。
推荐阅读
- java - Java中的泛型与接口
- laravel - Laravel:如何解析和处理路由?
- angular - 使用 GitHub 在 2 台计算机上处理 Angular CLI 项目
- python - 合并多个输入的模型
- java - 我可以在公共方法中声明私有变量吗?
- python - Python:比较列表,执行操作,创建新列表
- php - 减少 Woocommerce 中的产品长描述
- profiler - 线程视图在性能/cpu 分析器中有何用处?
- sql-server - 如何使用两个或更多用户实时更新我的 Datagridview?
- ios - Swift 4 UITableView 像 Apple Music 搜索