Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1047941
  • 博文数量: 288
  • 博客积分: 10306
  • 博客等级: 上将
  • 技术积分: 3182
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-12 17:00
文章分类

全部博文(288)

文章存档

2011年(19)

2010年(38)

2009年(135)

2008年(96)

我的朋友

分类: C/C++

2008-10-20 11:38:34

0905 WaitForSingleObject MsgWaitForMultipleObjects

想运行一个程序,等待结束,结果

if (CreateProcess(NULL,strExeCmd.GetBuffer(0),NULL,NULL,FALSE,
       0,NULL,NULL,&StartupInfo,&ProcessInfo))
 {
  WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
  }

但是其他的消息全部被堵塞了。
看到这个:

VC中利用多线程技术实现线程之间的通信

一个简单的办法就是把这个扔到线程里面去,让它自己折腾
不过那样的话又要考虑到线程通知主线程,也麻烦,找到资料:
shootingstars
菩提本无树,明镜亦非台。本来无一物,何处惹尘埃。尘埃乃虚幻,亦何惧之来?
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)
下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?

线程函数:

DWORD WINAPI ThreadProc(
    while(!bTerminate)
    {
        //
从一个链表中读取信息并且插入到CListCtrl
        // CListCtrl
的句柄是通过线程参数传递进来的
        for(;;)
       {
           ReadInfoFromList();
           InsertToCListCtrl();
        }
    }
}
主线程中使用CreateThread启动线程。

当想终止子线程时,在主线程中:
bTerminate = TRUE;
WaitForSingleObject(threadHandle, INFINITE);
可是,以运行到WaitForSingleObject,子线程就Crash了。

为什么呢?

问题原因:
后来我终于在InsertItem的反汇编中发现了如下的代码
call dword ptr [__imp__SendMessageA at 16 (7C141B54h)]
可见,InsertItem是必须借助消息循环来完成任务的。如果我们在主线程中WaitForSingleObject了,必然导致主线程阻塞,也就导致了消息循环的阻塞,最终导致工作线程Crash掉了*_*
解决方案:
为了解决在主线程中Wait的问题,微软专门设计了一个函数MsgWaitForMultipleObjects,这个函数即可以等待信号(thread,event,mutex等等),也可以等待消息(MSG)。即不论有信号被激发或者有消息到来,此函数都可以返回。呵呵,那么我的解决办法也就出来了。
将上面的WaitForSingleObject用下面的代码替换:
while(TRUE)
{
    DWORD result ;
    MSG msg ;
    result = MsgWaitForMultipleObjects(1, &readThreadHandle,
        FALSE, INFINITE, QS_ALLINPUT);
    if (result == (WAIT_OBJECT_0))
    {
        break;
    }
    else
    {
        PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
        DispatchMessage(&msg);
    }
}
总结:
如果在工作线程中有可能涉及到了消息驱动的API,那么不能在主线程中使用WaitForSingleObject一类函数,而必须使用上述的方案。


网上流传一个很广的例子,不过那个代码没有办法编译通过,找不到:THREADINFO
启动和等待进程结束 闻怡洋
我们在开发是经常需要在启动一个进程之后等待其结束后再继续运行。
在这里提供了一个名为Wait的函数,它会为你完成上面的功能。实现的思想是在启动进程后等待其结束,由于进程是一种资源,而资源的句柄在WIN32中可以作为核心量使用。你可以使用WaitForSingleObject等待核心量状态改变为有信号状态。对进程来讲当进程结束时其状态转变为有信号。

在本例中使用了一个单独的线程来启动进程并等待结束。
Wait()
BOOL Wait(CString szCmdLine)
{
    LPTHREADINFO pThreadInfo = new THREADINFO;
    CEvent *pThreadEvent = new CEvent(FALSE, TRUE);
    ASSERT_VALID(pThreadEvent);
    if(pThreadInfo)
    {
        pThreadInfo->pTermThreadEvent = pThreadEvent;
        pThreadInfo->strPathName = szCmdLine;
        AfxBeginThread(LaunchAndWait, pThreadInfo);
        WaitForSingleObject(pThreadEvent->m_hObject, INFINITE);
        return TRUE;
    }
    return FALSE;
}
LaunchAndWait()
UINT LaunchAndWait(LPVOID pParam)
{
    LPTHREADINFO pThreadInfo = (LPTHREADINFO) pParam;
    PROCESS_INFORMATION stProcessInfo;
    if(LaunchApplication(pThreadInfo->strPathName, &stProcessInfo))
    {
        HANDLE hThreads[2];
        hThreads[0] = pThreadInfo->pTermThreadEvent->m_hObject;
        hThreads[1] = stProcessInfo dot hProcess;
        DWORD dwIndex = WaitForMultipleObjects(2, hThreads, FALSE, INFINITE);
        CloseHandle(stProcessInfo.hThread);
        CloseHandle(stProcessInfo.hProcess);
        pThreadInfo->pTermThreadEvent->SetEvent();
        if(pThreadInfo)
            delete pThreadInfo;
    }
    else
        pThreadInfo->pTermThreadEvent->SetEvent();
    return 0;
}

LaunchApplication()
BOOL LaunchApplication(LPCTSTR pCmdLine, PROCESS_INFORMATION *pProcessInfo)
{
    STARTUPINFO stStartUpInfo;
    memset(&stStartUpInfo, 0, sizeof(STARTUPINFO));
    stStartUpInfo.cb = sizeof(STARTUPINFO);
    stStartUpInfo.dwFlags = STARTF_USESHOWWINDOW;
    stStartUpInfo.wShowWindow = SW_SHOWDEFAULT;
    return CreateProcess(NULL, (LPTSTR)pCmdLine, NULL, NULL, FALSE,
        NORMAL_PRIORITY_CLASS, NULL,
        NULL, &stStartUpInfo, pProcessInfo);
}
阅读(2095) | 评论(0) | 转发(0) |
0

上一篇:单子模式

下一篇:中国未来亚洲战略

给主人留下些什么吧!~~