MsgWaitForMultipleObjects和WaitForSingleObject的应用及其注意事项

35 篇文章 7 订阅
在WindowsGUI应用程序中,使用WaitForSingleObject等待子线程退出会导致主对话框的消息循环被阻塞,从而影响界面响应。文章提出使用MsgWaitForMultipleObjects代替,该方法允许线程在等待对象的同时检查消息队列,防止界面卡死。通过MsgWaitForMultipleObjects,可以在等待子线程结束的同时处理用户输入和其他消息。
摘要由CSDN通过智能技术生成

应用实例:

在主对话框退出时判断子线程是否安全退出。如果在主对话框中使用WaitForSingleObject()等待子线程退出,WaitForSingleObject()将阻断所有对话框消息循环,以致对话框消息循环阻塞界面卡死,这个不是我们预期的效果和想要完成的功能。

案例演示:

在主对话框函数中设置事件使其变为有信号状态。在主对话框中使用WaitForSingleObject()函数等待子线程结束,此时奇怪的一幕就会发生。WaitForSingleObject()会阻塞消息循环,故导致子线程TemPlcControllerModbusCommThread(LPVOID lParam)退出后return 0;之前的::SendMessage()消息不被主对话框所接收。

::PostMessage(pMainHwnd->GetSafeHwnd(), WM_QUIT_MDBS_COMMUNICATION_THREAD, WPARAM(pModbusConn->mPlcController.ThreadMark),0);
  return 0;
  mPlcController.mProEvent.SetEvent();//设定事件
  WaitForSingleObject(mPlcController.mProEvent,INFINITE);//等待线程结束
UINT CDoublePathWayReflowerControllerDlg::TemPlcControllerModbusCommThread(LPVOID lParam)
{
    CDoublePathWayReflowerControllerDlg* pModbusConn = (CDoublePathWayReflowerControllerDlg*)lParam;
    CWnd* pMainHwnd = AfxGetApp()->GetMainWnd();
    DWORD mEventQuit = 0;
    CSingleLock mLoopRw(&mCommCmutex);
    while (TRUE)
    {
        mEventQuit = WaitForSingleObject(pModbusConn->mPlcController.mProEvent.m_hObject, 0);
        if (mEventQuit == WAIT_OBJECT_0)
        {
            break;
        }
        /*while (WaitForSingleObject(pModbusConn->mPlcController.modbusThreadQuit.m_hObject, 50) == WAIT_OBJECT_0)
        {
            printf("Wait WriteDataSet To Plc controller Finished!\n");
        }*/

        /*Read Write Test Begine*/
    /*    pModbusConn->WriteAllQbitByStep(&pModbusConn->mPlcController, NUM_OUPUT_Q, pModbusConn->mPlcDataCommTalble.Table_ReadQ_bits, QOUT_OPEN);
        pModbusConn->DlgDelayUs(1);

        pModbusConn->WriteAllQbitByStep(&pModbusConn->mPlcController, NUM_OUPUT_Q, pModbusConn->mPlcDataCommTalble.Table_ReadQ_bits, QOUT_CLOSE);
        pModbusConn->DlgDelayUs(1);

        pModbusConn->WriteQbitsByMultiByte(&pModbusConn->mPlcController, NUM_OUPUT_Q, pModbusConn->mPlcDataCommTalble.Table_WriteMulti_Qbits, pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Qbits, QOUT_OPEN);

        pModbusConn->DlgDelayUs(1);
        pModbusConn->WriteQbitsByMultiByte(&pModbusConn->mPlcController, NUM_OUPUT_Q, pModbusConn->mPlcDataCommTalble.Table_WriteMulti_Qbits, pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Qbits, QOUT_CLOSE);*/

        /*pModbusConn->WriteFloatRegister(&pModbusConn->mPlcController,1000,2, pModbusConn->mPlcDataCommTalble.WriteTemFloatDataRegister, pModbusConn->mPlcDataCommTalble.Table_WriteTemDataRegisters,0);
        pModbusConn->DlgDelayUs(1);*/

        /*Read Write Test End*/
        /*pModbusConn->mPlcDataCommTalble.Table_ReadWordRegisters[0] = 1234;
        pModbusConn->WriteWordRegiste(&pModbusConn->mPlcController, 9000, 1, pModbusConn->mPlcDataCommTalble.Table_ReadWordRegisters, 0);
        printf("VW9000=%X\n", pModbusConn->mPlcDataCommTalble.Table_ReadWordRegisters[0]);*/
        mLoopRw.Lock();
        if (mLoopRw.IsLocked())
        {
            if (mManualWriteData==FALSE)
            {
                for (int i = 1; i <= PATHA_TEMZONE_NUM; i++)
                {
                    pModbusConn->ReadTempretureFromController(PATHA, i);
                }
                ::SendMessage(pMainHwnd->GetSafeHwnd(), WM_UPDATE_REAL_TEMPREUTRE, WPARAM(pModbusConn->mPlcDataCommTalble.ReadTemFloatDataRegister), 0);
                pModbusConn->DlgDelayUs(0);

                pModbusConn->ReadIbitsByMultiByte(&pModbusConn->mPlcController, 0, NUM_INPUT_I, pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Ibits);
                if (pModbusConn->mhWnd != NULL)
                {
                    ::SendMessage(pModbusConn->mhWnd, WM_UPDATE_IO_INPUT_STATUS, WPARAM(pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Ibits), 0);
                }
                pModbusConn->DlgDelayUs(0);
                pModbusConn->ReadQbitsByMultiByte(&pModbusConn->mPlcController, NUM_OUPUT_Q, pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Qbits);
                if (pModbusConn->mhWnd != NULL)
                {
                    ::SendMessage(pModbusConn->mhWnd, WM_UPDATE_IO_OUTPUT_STATUS, WPARAM(pModbusConn->mPlcDataCommTalble.Table_ReadMulti_Qbits), 0);
                }
            }
            else
            {
                SetEvent(pModbusConn->mPlcController.modbusThreadQuit);
            }
            
            
        }
        else
        {
            printf("TemPlcControllerModbusCommThread Wait mCommCmutex Unlock!\n");
        }
        mLoopRw.Unlock();
    }
    pModbusConn->DlgDelayUs(100);
    pModbusConn->mPlcController.ThreadMark = MDBS_THREAD_KILLER;
    ::PostMessage(pMainHwnd->GetSafeHwnd(), WM_QUIT_MDBS_COMMUNICATION_THREAD, WPARAM(pModbusConn->mPlcController.ThreadMark),0);
    return 0;

解决办法:

使用MsgWaitForMultipleObjects()替代WaitForSingleObject(),下面为微软MSDN中有关MsgWaitForMultipleObjects()的详细解读。

MsgWaitForMultipleObjects()介绍

MsgWaitForMultipleObjects

See Also

Message Queue Functions | MsgWaitForMultipleObjectsEx | WaitForMultipleObjects

Requirements

OS Versions: Windows CE 1.0 and later.

Header: Winbase.h.

Link Library: Msgque.lib.

Thisfunction returns when one of the specified objects is in the signaled state, or when the time-out interval elapses. This function does not return if there is unread input of the specified type in the queue. It returns only when new input arrives.

DWORD MsgWaitForMultipleObjects(DWORDnCount,LPHANDLEpHandles,BOOLfWaitAll,DWORDdwMilliseconds,DWORDdwWakeMask);

Parameters

nCount

[in] Specifies the number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS

minus one.

pHandles

[in] Pointer to an array of object handles. For a list of the object types

whose handles can be specified, see the following Remarks section. The array can

contain handles of objects of different types.

fWaitAll

[in] Unsupported; set to FALSE.

dwMilliseconds

[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the criteria specified by the dwWakeMask parameter have not been met. If dwMilliseconds is zero, the function

tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never

elapses.

dwWakeMask

[in] Specifies input types for which an input event object handle will be

added to the array of object handles. This parameter can be any combination of

the following values.

Value

Description

QS_ALLEVENTS

An input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue.

QS_ALLINPUT

Any message is in the queue.

QS_HOTKEY

A WM_HOTKEY message is in the queue.

QS_INPUT

An input message is in the queue.

QS_KEY

A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue.

QS_MOUSE

A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).

QS_MOUSEBUTTON

A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).

QS_MOUSEMOVE

A WM_MOUSEMOVE message is in the queue.

QS_PAINT

A WM_PAINT message is in the queue.

QS_POSTMESSAGE

A posted message (other than those just listed) is in the queue.

QS_SENDMESSAGE

A message sent by another thread or application is in the queue.

QS_TIMER

A WM_TIMER message is in the queue.

Return Values

If the function succeeds, the return value indicates the event that caused

the function to return. The successful return value is one of the following:

WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount –1)

The return value minus WAIT_OBJECT_Zero indicates the pHandles array

index of the object that satisfied the wait.

WAIT_OBJECT_0 + nCount

New input of the type specified in the dwWakeMask parameter is available in the thread's input queue. Functions such as PeekMessage and GetMessage mark messages in the queue as old

messages. Therefore, after you call one of these functions, a subsequent call to MsgWaitForMultipleObjects will not return until new input of the

specified type arrives.

This value is also returned upon the occurrence of a system event that

requires the thread's action, such as foreground activation. Therefore, MsgWaitForMultipleObjects can return even though no appropriate input is available and even if dwWaitMask is set to 0. If this occurs, call PeekMessage or GetMessage to process the system event before trying the call to MsgWaitForMultipleObjects again.

WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount –1)

The return value minus WAIT_ABANDONED_Zero indicates the pHandles

array index of an abandoned mutex object that satisfied the wait.

WAIT_TIMEOUT

The time-out interval elapsed and the conditions specified by the dwWakeMask parameter were not satisfied.

0xFFFFFFFF indicates failure. To get extended error information, call GetLastError.

Remarks

The MsgWaitForMultipleObjects function is implemented as a macro that calls MsgWaitForMultipleObjectsEx, passing 0 in the dwFlags parameter.

The MsgWaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters an efficient wait state, using very little processor time while waiting for the conditions of the wait criteria to be met.

Before returning, a wait function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When fWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The MsgWaitForMultipleObjects function can specify handles of the following object types in the pHandles array:

  • Event

  • Mutex

  • Semaphore

  • Process

  • Thread

  • Critical section

The QS_POSTMESSAGE flag is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages.

Requirements

OS Versions: Windows CE 1.0 and later.

Header: Winbase.h.

Link Library: Msgque.lib.

WaitForSingleObject()介绍

WaitForSingleObject

See Also

MsgWaitForMultipleObjects | MsgWaitForMultipleObjectsEx | WaitForMultipleObjects | CreateEvent | CreateFile | PulseEvent | ResetEvent | SetEvent | Sleep

Requirements

OS Versions: Windows CE 1.0 and later.

Header: Winbase.h.

Link Library: Coredll.lib.

This function returns when the specified object is in the signaled state or when the time-out interval elapses.

DWORDWaitForSingleObject( HANDLEhHandle, DWORDdwMilliseconds);

Parameters

hHandle

[in] Handle to the object. For a list of the object types whose handles can

be specified, see the Remarks section.

dwMilliseconds

[in] Specifies the time-out interval, in milliseconds. The function returns

if the interval elapses, even if the object's state is nonsignaled. If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values

If the function succeeds, the return value indicates the event that caused

the function to return. The following table shows the possible return values.

Value

Description

WAIT_OBJECT_0

The state of the specified object is signaled.

WAIT_TIMEOUT

The time-out interval elapsed, and the object's state is nonsignaled.

WAIT_FAILED indicates failure. Waiting on an invalid handle causes WaitForSingleObject to return WAIT_FAILED.

To get extended error information, call GetLastError.

Remarks

Windows CE 1.0 through 2.12 do not support waiting for semaphores, change notification objects, input, and timers. Windows CE 3.0 and later support waiting for semaphores.

For Windows CE 1.0 and 1.01, this function cannot wait on process or thread handles.

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters an efficient wait state. The thread consumes very little processor time while waiting for the object state to become signaled or the time-out interval to elapse.

The time-out value needs to be a positive number between zero and 0x7FFFFFFF. The maximum time-out value not equal to infinity is 0x7FFFFFFF. The infinite time-out value is 0xFFFFFFFF. Any time-out value between 0x7FFFFFFF and 0xFFFFFFFF — that is, values from 0x80000000 through 0xFFFFFFFE — is equivalent to 0x7FFFFFFF. If you need a bigger time-out value than the maximum of 0x7FFFFFFF, use the value for infinity (0xFFFFFFFF).

Before returning, a wait function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObject function can wait for the following objects:

  • Event

Mutex

Semaphore

Process

  • Thread

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. For example, the Dynamic Data Exchange (DDE) protocol and the COM function CoInitialize both indirectly create windows that can cause a deadlock. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.

Requirements

OS Versions: Windows CE 1.0 and later.

Header: Winbase.h.

Link Library: Coredll.lib.

WaitForMultipleObjects()介绍

See Also

MsgWaitForMultipleObjects | MsgWaitForMultipleObjectsEx | WaitForSingleObject | CreateEvent | CreateFile | CreateMutex | CreateProcess | CreateThread | PulseEvent | ResetEvent | SetEvent

Requirements

OS Versions: Windows CE 1.01 and later.

Header: Winbase.h.

Link Library: Nk.lib.

This function returns a value when either any one of the specified objects is in the signaled state, or the time-out interval elapses.

DWORD WaitForMultipleObjects(DWORDnCount, CONST HANDLE* lpHandles, BOOLfWaitAll, DWORDdwMilliseconds);

Parameters

nCount

[in] Specifies the number of object handles in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.

lpHandles

[in] Pointer to an array of object handles. For a list of the object types

whose handles can be specified, see the Remarks section. The array can contain

handles of objects of different types.

fWaitAll

[in] Specifies the wait type. This parameter must be set to FALSE. This

causes function to return when the state of any one of the objects set to is

signaled. The return value indicates the object whose state caused the function

to return.

dwMilliseconds

[in] Specifies the time-out interval in milliseconds. The function returns if the interval elapses, even if the conditions specified by the bWaitAll parameter are not met. If dwMilliseconds is zero, the function tests the

states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value

Description

WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount –1)

The return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that satisfied the wait. If more than one object became signaled during the call, this is the array index of the signaled object with the smallest index value of all the signaled objects.

WAIT_TIMEOUT

The time-out interval elapsed and the condition specified by the fWaitAll parameter is not satisfied.

WAIT_FAILED indicates failure. To get extended error information, call GetLastError.

Remarks

Windows CE 1.0 through 2.12 do not support waiting for semaphores, change notification objects, input, and timers. Windows CE 3.0 and later supports waiting for semaphores.

For Windows CE 1.0 and 1.01, this function cannot wait on process or thread handles.

The WaitForMultipleObjects function determines whether the wait criteria were met. If the criteria were not met, the calling thread enters an efficient wait state, consuming very little processor time while waiting for the criteria to be met.

The time-out value needs to be a positive number between zero and 0x7FFFFFFF. The maximum time-out value not equal to infinity is 0x7FFFFFFF. The infinite time-out value is 0xFFFFFFFF. Any time-out value between 0x7FFFFFFF and 0xFFFFFFFF—that is, values from 0x80000000 through 0xFFFFFFFE—is equivalent to 0x7FFFFFFF. If you need a bigger time-out value than the maximum of 0x7FFFFFFF, use the value for infinity (0xFFFFFFFF).

Before returning, a wait function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. When fWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The WaitForMultipleObjects function can specify handles of any of the following object types in the lpHandles array:

  • Event

Mutex

Process

Thread

  • Semaphore

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. For example, the Dynamic Data Exchange (DDE) protocol and the COM function CoInitialize both indirectly create windows that can cause a deadlock. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForMultipleObjects.

Requirements

OS Versions: Windows CE 1.01 and later.

Header: Winbase.h.

Link Library: Nk.lib.

See Also

MsgWaitForMultipleObjects | MsgWaitForMultipleObjectsEx | WaitForSingleObject | CreateEvent | CreateFile | CreateMutex | CreateProcess | CreateThread | PulseEvent | ResetEvent | SetEvent


Last updated on Wednesday, September 14, 2005

© 2005 Microsoft Corporation. All rights reserved.

MsgWaitForMultipleObjects()封装

void CDoublePathWayReflowerControllerDlg::MsgWaitForMultipleObjectsEx(BOOL mWaitPremise, HANDLE mEventHandle)
{
    while (mWaitPremise==TRUE)
    {

        DWORD result;
        MSG msg;

        result = MsgWaitForMultipleObjects(1, &mEventHandle, FALSE, INFINITE, QS_SENDMESSAGE/*QS_ALLINPUT*/);

        if (result == (WAIT_OBJECT_0))
        {
            break;
        }
        else
        {
            PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
            DispatchMessage(&msg);
        }
    }
}

MsgWaitForMultipleObjectsEx()应用

  mPlcController.mProEvent.SetEvent();
  /*Wait Modbus Communication Thread Quit safty*/
  printf("Pre Wati Modbus Communication Thread Quit Safty!\n");
  MsgWaitForMultipleObjectsEx(TRUE, mPlcController.ModBusThread->m_hThread);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值