Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 工作线程如何与主UI线程通信?_C++_Multithreading_Mfc - Fatal编程技术网

C++ 工作线程如何与主UI线程通信?

C++ 工作线程如何与主UI线程通信?,c++,multithreading,mfc,C++,Multithreading,Mfc,工作线程与主UI线程通信的最佳方式是什么 小结:我的C++/MFC应用程序是基于对话框的。要进行冗长的计算,主UI线程将创建几个辅助线程。工作线程在计算过程中进行时,会将其进度报告给主UI线程,然后主UI线程会显示进度 这适用于共享内存中的数字进度值(由工作人员编写,由UI读取),但我在处理文本进度消息时遇到了问题。我尝试的解决方案已经经过了多次迭代,但似乎都不起作用 我让UI线程将指向控件的指针传递给工人,工人直接更新UI。这不是很有效,而且似乎是错误的方法 我让工作人员使用SendMessa

工作线程与主UI线程通信的最佳方式是什么

小结:我的C++/MFC应用程序是基于对话框的。要进行冗长的计算,主UI线程将创建几个辅助线程。工作线程在计算过程中进行时,会将其进度报告给主UI线程,然后主UI线程会显示进度

这适用于共享内存中的数字进度值(由工作人员编写,由UI读取),但我在处理文本进度消息时遇到了问题。我尝试的解决方案已经经过了多次迭代,但似乎都不起作用

  • 我让UI线程将指向控件的指针传递给工人,工人直接更新UI。这不是很有效,而且似乎是错误的方法

  • 我让工作人员使用SendMessage向UI线程的窗口发送消息。这个僵局。(SendMessage在处理完消息后才会返回。)

  • 与(2)相同,除了使用UI线程窗口的PostMessage。这起作用了,有一段时间,信息丢失了。(PostMessage立即返回。)进一步的调查显示消息队列的配额(默认为10000)被超过

  • 我增加了邮件队列的配额(注册表中的变量HKEY\U LOCAL\U MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERPostMessageLimit),但丢失邮件的数量没有改变

  • 我将每个工作线程缓冲区消息放在4kbyte缓冲区中,并在缓冲区填满时发送PostMessage。此操作失败,因为UI线程从未收到任何消息。当我将缓冲区大小增加到64 KB时也是如此

  • 工作线程以“最低”优先级运行,UI线程以“正常”优先级运行。工作线程正在发送代码如下的消息

    UIMessage *pUI=new UIMessage; // so it won't go out of scope (main dialog will delete it)
    pUI->buffer=traceLineBuffer; pUI->nOutputs=traceN;
    BOOL ok=::PostMessage(hWndMainDlg,TraceLineMsg,(WPARAM)pUI, NULL/*lParam*/);
    
    BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
    ...
    ON_MESSAGE(TraceLineMsg,OnTraceLineMsg)
    ...
    END_MESSAGE_MAP()
    
    LRESULT CMainDlg::OnTraceLineMsg(WPARAM wParam, LPARAM lParam)
    {
        UIMessage *pUI=(UIMessage *)wParam;
        char *p=pUI->buffer;
        // PROCESS BUFFER
        delete[] pUI->buffer;
        delete pUI;
        return 0;
    }
    
    UI正在接收它们,代码如下

    UIMessage *pUI=new UIMessage; // so it won't go out of scope (main dialog will delete it)
    pUI->buffer=traceLineBuffer; pUI->nOutputs=traceN;
    BOOL ok=::PostMessage(hWndMainDlg,TraceLineMsg,(WPARAM)pUI, NULL/*lParam*/);
    
    BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
    ...
    ON_MESSAGE(TraceLineMsg,OnTraceLineMsg)
    ...
    END_MESSAGE_MAP()
    
    LRESULT CMainDlg::OnTraceLineMsg(WPARAM wParam, LPARAM lParam)
    {
        UIMessage *pUI=(UIMessage *)wParam;
        char *p=pUI->buffer;
        // PROCESS BUFFER
        delete[] pUI->buffer;
        delete pUI;
        return 0;
    }
    
    问题:

  • 在可能出现数千条文本报告的情况下,工人发布进度报告的首选方式是什么

  • 为什么我不能增加队列中post消息的配额

  • 为什么主UI线程似乎从未接收缓冲区中的消息,即使发送消息的机制与发布单个报告相同


  • 64位Windows 7、Visual Studio 2010、本机C++/MFC

    ,主线程位于WaitForMultipleObjects调用中,不会处理任何消息,也不会更新任何控件或其他窗口。解决方案是:不要这样做。

    在GUI上发布进度报告的速度要比用户能够理解的速度快,这没有多大意义。当其他线程中有大量活动时,通常会使用GUI计时器轮询线程中的进度变量,因此每500毫秒更新一次GUI控件

    这是计时器轮询实际上具有优势的极少数情况之一。您可以获得peridoc进度报告,而不会在GUI Windows消息队列中塞满更新。例如,uTorrent客户端(存在大量网络活动的地方)使用此方案-尝试更新收到的每个网络协议单元上的GUI下载统计信息肯定会填满GUI


    (5)中的缓冲方案应该是有效的。我经常通过将对象指针加载到LPARAM或WPARAM中,在工作线程中新建大型数据项,并在显示后在GUI中删除它们,从而将大型数据项传输到主GUI线程。您的(5)应该已经工作了,并且至少减少了进度数据传输的开销。我只能假设要显示的数据量仍然太大,因此GUI线程仍然无法跟上:(

    Windows上的MFC工作线程有多个与主线程通信的选项。您有标准的线程信号和同步(互斥、信号量等),使用方便,性能更高的机制

    // syncronization
    {
        CSingleLock lock(&sharedCriticalSection,TRUE);
        sharedList.push_back(msg);
    }
    // other thread(s) are blocked/pending or you send an event or message to signal
    
    // messages
    Data* data = new Data(payload);
    PostMessage(hWnd, REGISTERED_MESSAGE, 0, (LPARAM)data);
    // target window handles message and deletes data 
    // if it is not blocked or too slow and the queue overflows
    
    // skipping lots of IO completion port boilerplate and showing the key methods
    messagePort = CreateIoCompletionPort(...);
    ...
    GetQueuedCompletionStatus(messagePort,...);
    ...
    PostQueuedCompletionStatus(messagePort,...);
    
    如果您阻塞或忙着等待线程完成,它们都不会完成很多工作,也不会提高您的性能或响应能力

    对你的意见的评论:

  • 不要让工人触摸GUI
  • 不要使用来自工作线程的SendMessage
  • PostMessage适用于低容量,只要UI能够跟上并且不被阻塞
  • 如果你认为这需要改变,你应该重新考虑你的解决方案。少发送或使用更高性能的选项
  • 如果UI没有被阻止,整合消息可能会有所帮助
  • 回答你的问题:

  • 重新评估是否真的需要在一次突发中发送数千条消息。用户每秒需要多少更改?如果需要发送所有更改,请查看I/O完成端口机制
  • 我不会尝试,它可能会起作用,除非
  • 您的主UI线程在等待工作线程在WaitForMultipleObjects中完成时被阻止,而您的工作线程和其他事件在被阻止时生成的队列消息数必须超过最大值

  • 发布消息是一种方法。但您是否考虑过大幅减少消息数量?为什么不每100或1000条消息更新一次?您所采取的方法是正确的,但发送足够的消息以超过队列限制确实没有意义。唯一可能导致未收到已发布消息的是溢出g队列限制或阻止主线程,如在睡眠或等待..调用中。在发布这些消息时,主线程在做什么?您是否也为每条消息分配了另一个traceLineBuffer?koodawg:我确实通过将消息缓冲在(5)中来减少消息的数量.ScottMcP MVP:在工作线程完成之前,主线程处于WaitForMultipleObjects中。可能这就是问题所在。是的,为每条消息分配了一条新消息和缓冲区,您可以从我在OnTraceLineMsg中删除它们中看到。我应该