Winapi MFC:如何从主线程使用MsgWaitForMultipleObjects()来等待多个线程完成使用SendMessage()的操作?

Winapi MFC:如何从主线程使用MsgWaitForMultipleObjects()来等待多个线程完成使用SendMessage()的操作?,winapi,mfc,Winapi,Mfc,我有一个主线程,根据用户从主UI中选择的内容触发其他几个线程来完成各种工作。通常我会使用WaitForMultipleObjects(),将bWaitAll设置为TRUE。但是,在这种情况下,其他线程将把输出记录到另一个窗口,该窗口使用互斥锁确保线程一次只输出一个。该过程的一部分使用SendMessage()发送获取文本大小,并将文本发送到窗口,如果使用WaitForMultipleObjects(),该窗口将挂起,因为它是从主UI线程运行的。因此,我转而使用带有QS_SENDMESSAGE标志

我有一个主线程,根据用户从主UI中选择的内容触发其他几个线程来完成各种工作。通常我会使用
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()
with
bWaitAll=FALSE
是正确的解决方案。将线程句柄放入数组中,每次等待指示线程已完成时,都从数组中删除该线程。保持循环直到数组为空。每当等待指示挂起消息时,都会泵送消息队列。通常-是的,您永远不必使用bWaitAll set为TRUE。使用
bWaitAll=FALSE
并根据需要更改等待数组。如果线程/进程发出信号,当然会从数组中删除句柄。但对于具体任务,所有解决方案都是错误的。您不需要等待线程句柄。您需要为具有ref count的任务创建公共结构。当线程退出时,它释放ref count。当struct(没有更多线程)将消息发布到您的窗口