Winapi MFC:如何从主线程使用MsgWaitForMultipleObjects()来等待多个线程完成使用SendMessage()的操作?
我有一个主线程,根据用户从主UI中选择的内容触发其他几个线程来完成各种工作。通常我会使用Winapi MFC:如何从主线程使用MsgWaitForMultipleObjects()来等待多个线程完成使用SendMessage()的操作?,winapi,mfc,Winapi,Mfc,我有一个主线程,根据用户从主UI中选择的内容触发其他几个线程来完成各种工作。通常我会使用WaitForMultipleObjects(),将bWaitAll设置为TRUE。但是,在这种情况下,其他线程将把输出记录到另一个窗口,该窗口使用互斥锁确保线程一次只输出一个。该过程的一部分使用SendMessage()发送获取文本大小,并将文本发送到窗口,如果使用WaitForMultipleObjects(),该窗口将挂起,因为它是从主UI线程运行的。因此,我转而使用带有QS_SENDMESSAGE标志
WaitForMultipleObjects()
,将bWaitAll设置为TRUE。但是,在这种情况下,其他线程将把输出记录到另一个窗口,该窗口使用互斥锁确保线程一次只输出一个。该过程的一部分使用SendMessage()
发送获取文本大小,并将文本发送到窗口,如果使用WaitForMultipleObjects()
,该窗口将挂起,因为它是从主UI线程运行的。因此,我转而使用带有QS_SENDMESSAGE
标志的MsgWaitForMultipleObjects
,唯一的问题是bWaitAll的逻辑,它表示只有当所有对象都发出信号且发生输入事件时才会返回(而不是在所有对象都发出信号或发生输入事件时返回). 如果逻辑是或,这应该是有效的:
DWORD waitres=WAIT_FAILED;
while (1)
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
// mfc message pump
if (!theApp.PumpMessage()) {
// program end request
// TO DO
}
}
// MFC idel processing
LONG lidlecount = 0;
while (theApp.OnIdle(lidlecount++));
// our wait
waitres = ::MsgWaitForMultipleObjects(threadcount, threadhandles, TRUE, INFINITE, QS_SENDMESSAGE);
// check if ended due to message
if (waitres!=WAIT_OBJECT_0+threadcount) {
// no, exit loop
break;
}
}
我想知道从主线程处理这个问题的正确方法是什么,而不是先触发一个线程,然后再触发其他线程?我考虑使用bWaitAll FALSE,然后使用WaitForMultipleObjects()
,将bWaitAll设置为TRUE,将dwmillizes设置为0(或1),并检查结果是否完成。如果没有,则需要循环回循环的顶部,然后再循环到MsgWaitForMultipleObjects()
,当使用bWaitAll FALSE时,如果多个线程中的一个线程已完成,则会立即返回(假设10个线程中的1个线程已完成,我可以如上所述检查所有线程是否已完成,但当返回bWaitAll FALSE时,它将返回,而不是等待)
那么,处理在MFC应用程序的主线程中等待多个线程(使用SendMessage()
)完成的正确方法是什么呢
谢谢
那么,处理等待多个线程运行的正确方法是什么呢
完整的
需要创建一些结构,带有引用计数,并将指向该结构的指针传递给每个线程。这里可能还存在一些常见的任务数据。以及main(GUI)中某个窗口的HWND线程。当工作线程退出时-它释放对象上的引用。当最后一个线程退出时-删除对象并从主线程向窗口发布一些消息
所以我们不需要存储线程句柄(只需关闭它)并等待多个句柄,而是在所有线程完成任务时得到一些窗口消息
代码示例
struct Task
{
HWND _hwnd;
LONG _dwRefCount = 1;
// some common task data probably ..
Task(HWND hwnd) : _hwnd(hwnd) {}
~Task() {
PostMessageW(_hwnd, WM_USER, 0, 0);// WM_USER as demo only
}
void AddRef(){
InterlockedIncrementNoFence(&_dwRefCount);
}
void Release(){
if (!InterlockedDecrement(&_dwRefCount)) delete this;
}
};
ULONG CALLBACK WorkThread(void* pTask)
{
WCHAR sz[16];
swprintf_s(sz, _countof(sz), L"%x", GetCurrentThreadId());
MessageBoxW(0, L"working...", sz, MB_ICONINFORMATION|MB_OK);
reinterpret_cast<Task*>(pTask)->Release();
return 0;
}
void StartTask(HWND hwnd, ULONG n)
{
if (Task* pTask = new Task(hwnd))
{
do
{
pTask->AddRef();
if (HANDLE hThread = CreateThread(0, 0, WorkThread, pTask, 0, 0))
{
CloseHandle(hThread);
}
else
{
pTask->Release();
}
} while (--n);
pTask->Release();
}
}
struct任务
{
HWND HWND;
长_dwRefCount=1;
//一些常见的任务数据可能。。
任务(HWND-HWND):\u-HWND(HWND){
~Task(){
PostMessageW(_-hwnd,WM-u-USER,0,0);///WM-u-USER仅作为演示
}
void AddRef(){
联锁增量围栏(&_dwRefCount);
}
无效释放(){
如果(!InterlocatedDecrement(&_dwRefCount))删除此项;
}
};
ULONG回调工作线程(void*pTask)
{
WCHAR-sz[16];
swprintf_s(sz,_countof(sz),L“%x”,GetCurrentThreadId());
MessageBoxW(0,L“正在工作…”,sz,MB|U图标信息| MB|U OK);
重新解释铸造(pTask)->释放();
返回0;
}
无效起始任务(HWND HWND,ULONG n)
{
if(任务*pTask=新任务(hwnd))
{
做
{
pTask->AddRef();
if(HANDLE-hThread=CreateThread(0,0,工作线程,pTask,0,0))
{
CloseHandle(hThread);
}
其他的
{
pTask->Release();
}
}而(--n);
pTask->Release();
}
}
使用MsgWaitForMultipleObjects()
withbWaitAll=FALSE
是正确的解决方案。将线程句柄放入数组中,每次等待指示线程已完成时,都从数组中删除该线程。保持循环直到数组为空。每当等待指示挂起消息时,都会泵送消息队列。通常-是的,您永远不必使用bWaitAll set为TRUE。使用bWaitAll=FALSE
并根据需要更改等待数组。如果线程/进程发出信号,当然会从数组中删除句柄。但对于具体任务,所有解决方案都是错误的。您不需要等待线程句柄。您需要为具有ref count的任务创建公共结构。当线程退出时,它释放ref count。当struct(没有更多线程)将消息发布到您的窗口