FIX: CSyncObject::Lock Always Returns TRUE for Finite Waits

Last reviewed: September 19, 1997
Article ID: Q141533
4.00       | 4.00
WINDOWS NT | WINDOWS kbprg kbbuglist kbfixlist kbcode

The information in this article applies to:

  • The Microsoft Foundation Classes(MFC) included with: Microsoft Visual C++, 32-bit Edition, version 4.0

SYMPTOMS

The CSyncObject::Lock function always returns TRUE for finite values of timeout intervals. This happens even if the synchronization object is in a non-signaled state.

CAUSE

CSyncObject::Lock is supposed to return FALSE only when the synchronization object is in a non-signaled state. The current implementation of this function makes a call to ::WaitForSingleObject and returns FALSE only when ::WaitForSingleObject returns WAIT_FAILED. This is incorrect.

::WaitForSingleObject returns WAIT_FAILED only when the call itself fails. When it succeeds, it can return a variety of values, with only WAIT_OBJECT_0 indicating that the synchronization object is in a signaled state.

CSyncObject::Lock is a virtual function that is overridden only in the case of CCriticalSection. Hence the problem arises if you work with a CEvent, CMutex, or a CSemaphore object. The problem also comes up if you work with the CSingleLock class and call CSingleLock::Lock. This is because CSingleLock::Lock calls CSyncObject::Lock through its synchronization object.

In the case of finite timeout intervals, if the object is non-signaled, ::WaitForSingleObject returns WAIT_TIMEOUT. The CSyncObject::Lock should return FALSE but its current implementation returns TRUE. The return value from the Lock function is also TRUE when ::WaitForSingleObject returns WAIT_ABANDONED indicating that the thread that owned this synchronization object (a CMutex) terminated before releasing it.

RESOLUTION

The easiest way to fix the problem is to derive a new class from the synchronization object class that is being used (CEvent, CMutex, or CSemaphore). The only function that needs to be overridden is the CSyncObject::Lock function. Because this function is virtual, if you work with an object of your derived class, your derived class' implementation of Lock will be called. The Lock function in the new class (assuming it is called CMyEvent) should be implemented as:

BOOL CMyEvent::Lock(DWORD dwTimeout) {

  if (::WaitForSingleObject(m_hObject, dwTimeout) == WAIT_OBJECT_0)
    return TRUE;
  else
    return FALSE;
}

Please see the "Sample Code" section of this article for an illustration showing how to work around the problem. The sample code gives the definition of a class derived from the CEvent class and its implementation.

In the case of CMutex and CSemaphore, you need to proceed in the same manner. You need to derive new classes and override the Lock function in an identical fashion.

The correct CSyncObject::Lock :

BOOL CSyncObject::Lock(DWORD dwTimeout) {

  if (::WaitForSingleObject(m_hObject, dwTimeout) ==  WAIT_OBJECT_0)
    return TRUE;
  else
    return FALSE;
}

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This bug was corrected in Visual C++ 4.1.

REFERENCES

Sample Code

/* Compile options needed: Default Options
*/


// The Myevent.h File

#ifndef _MY_EVENT_
#define _MY_EVENT_

class CMyEvent : public CEvent {
      DECLARE_DYNAMIC(CMyEvent)

// Constructor
public:
      CMyEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE,
               LPCTSTR lpszName = NULL,
               LPSECURITY_ATTRIBUTES lpsaAttribute = NULL) :
               CEvent(bInitiallyOwn, bManualReset, lpszName,
                      lpsaAttribute)
               { }

// Operations
public:
      BOOL virtual Lock (DWORD dwTimeout = INFINITE);
};

#endif

// The Myevent.cpp File

#include "stdafx.h"
#include <afxmt.h>
#include "myevent.h"

IMPLEMENT_DYNAMIC (CMyEvent, CEvent)

BOOL CMyEvent::Lock(DWORD dwTimeout) {

  if (::WaitForSingleObject(m_hObject, dwTimeout) ==  WAIT_OBJECT_0)
    return TRUE;
  else
    return FALSE;
}


Additional reference words: CSyncObject 4.00 Lock WAIT_TIMEOUT Windows 95
4.10
KBCategory: kbprg kbbuglist kbfixlist kbcode
KBSubcategory: MFCThreadIss vcbuglist400 vcfixlist410
Keywords : MFCThreadIss vcbuglist400 vcfixlist410 kbbuglist kbcode kbfixlist kbprg
Technology : kbMfc
Version : 4.00 | 4.00
Platform : NT WINDOWS
Solution Type : kbfix


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: September 19, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.