临界区中的 DoModal

Posted

技术标签:

【中文标题】临界区中的 DoModal【英文标题】:DoModal in critical section 【发布时间】:2015-03-26 16:39:38 【问题描述】:

在并行循环中,有一个临界区。我尝试在关键部分使用 DoModal 执行 mfc 对话框,但是由于主线程等待并行线程,因此我的对话框无法显示和执行。为了打破这种依赖关系,我创建了一个可执行文件并将其作为并行循环中的进程运行。当进程显示对话框并获取信息时。它返回,其他线程继续运行。

但是我的团队领导坚持认为有更好的方法可以做到这一点,但经过数小时的搜索后我无法弄清楚:\

我尝试了一个单独的并行线程。它没有用。 我试过 CWinThread (谷歌说它是 gui 线程 :\ 没有帮助) 我厌倦了创建一个 exe 并运行它。那行得通:)

int someCriticDialog()

  #pragma omp critic (showCriticDlg)
  
   CMyDialog ccc;
   ccc.DoModal();
   /* However the code below works
      CreateProcess("someCriticDlg.exe", null, &hProcess);
      WaitForSingeObject(hProcess, INFINITE);
   */
  


#pragma omp parallel
for (int i = 0; i < 5; i++)
  someCriticDialog();

【问题讨论】:

【参考方案1】:

假设问题出在这里:

void trouble_maker() 

    Sleep(10000);//application stops for 10 seconds

您可以使用 PostMessage + PeekMessage + modal dialog 通过 GUI 窗口等待它完成:

void PumpWaitingMessages()

    MSG msg;
    while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
        if (!AfxGetThread()->PumpMessage())
            return;


BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    ON_COMMAND(2000, OnDoSomething)
    ON_COMMAND(IDCANCEL, OnCancel)
END_MESSAGE_MAP()

CMyDialog::CMyDialog(CWnd* par /*=NULL*/) : CDialog(IDD_DIALOG1, par)

    working = false;
    stop = false;


BOOL CMyDialog::OnInitDialog()

    BOOL res = CDialog::OnInitDialog();

    //call the function "OnDoSomething", but don't call it directly
    PostMessage(WM_COMMAND, 2000, 0);

    return res;


void CMyDialog::OnCancel()

    if (working)
    
        stop = true;
    
    else
    
        CDialog::OnCancel();
    


void CMyDialog::OnDoSomething()

    HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trouble_maker, NULL, 0, NULL);
    working = true;
    for (;;)
    
        if (WAIT_TIMEOUT != WaitForSingleObject(h, 100)) break;
        PumpWaitingMessages();
        //update progress bar or something...

        if (stop)
        
            //terminate if it's safe
            //BOOL res = TerminateThread(h, 0);
            //CloseHandle(h);
            //CDialog::OnCancel();
            //return;
        
    

    working = false;
    MessageBox("done");

【讨论】:

死锁发生在 DoModal 之后。泵消息没有变化。我可能会尝试创建另一个线程来泵送消息,直到有信号停止。 这是有道理的。我的回答完全是垃圾,我改了。 如果我调用 CWinThread->PumpMessage() 甚至在它自己的单独线程中。它会阻塞。 我有一种感觉,您正在从 Dialog 的构造函数或构造函数之前调用某个函数。试试上面的例子,看看你能不能让它工作。不然我不知道你的代码是怎么排列的。

以上是关于临界区中的 DoModal的主要内容,如果未能解决你的问题,请参考以下文章

同步互斥的实现

Linux内核设计与实现——内核同步

完成临界区互斥的根本办法

自旋锁的临界区都有哪些功能不能使用?

9内核同步介绍

java 多线程怎么深入?