DOCUMENT:Q151869 04-AUG-2001 [visualc] TITLE :PRB: Incorrect Usage of CSingleLock May Lock Up Mutex Object PRODUCT :Microsoft C Compiler PROD/VER:winnt:4.1 OPER/SYS: KEYWORDS:kbMFC kbThread kbVC410 kbGrpDSMFCATL ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - The Microsoft Foundation Classes (MFC), used with: - Microsoft Visual C++, 32-bit Editions, version 4.1 ------------------------------------------------------------------------------- SYMPTOMS ======== The CSingleLock class can be used with a CMutex object. An attempt to free the Mutex object by making a call to the documented function CSingleLock::Unlock(LONG, LPLONG) locks up the Mutex. The Mutex is not released even when the CSingleLock object is destroyed. Instead, the call to CSingleLock::Unlock(void) successfully frees the Mutex. CAUSE ===== There is a Boolean variable kept in the class CSingleLock - m_bAcquired. This variable keeps track of the state of the synchronization object. In the case of Mutexes, a value of TRUE (.T.) means that the Mutex object is owned by a thread. The variable is set to FALSE (.F.) when the Mutex is freed. There are two versions of CSingleLock::Unlock and two versions for CSyncObject::Unlock. One version takes no arguments, while the other one takes two: LONG and LPLONG. CSingleLock::Unlock makes a call to CSyncObject::Unlock only if the m_bAcquired member of CSingleLock is set to TRUE. Of the two versions of CSingleLock::Unlock, the latter version, with two arguments, should be used only with CSingleLock associated with CSemaphore objects. When used on a CSingleLock object associated with a CMutex, it just returns TRUE. This value is interpreted by CSingleLock::Unlock as though the object got freed and it sets its m_bAcquired member to FALSE. This causes the Mutex to lock up, because any future calls to CSingleLock::Unlock see m_bAcquired to be FALSE and the call to CSyncObject::Unlock is not made. When CSingleLock's destructor gets called, it calls Unlock. However, the same sequence of events prevents the Mutex from being freed. RESOLUTION ========== The first version of CSingleLock::Unlock, the one that takes no arguments, should be used. This calls CSyncObject::Unlock(void). This is a virtual function that calls CMutex::Unlock, that, in turn, calls ::ReleaseMutex to free the Mutex object. STATUS ====== This behavior is by design. MORE INFORMATION ================ Sample Code ----------- The following code demonstrates the problem: //....... CSingleLock* sLock = new CSingleLock (&GlobalMutex); sLock->Lock(); //... sLock->Unlock(1); //... delete sLock; //....... This code should be changed to: //...... CSingleLock* sLock = new CSingleLock (&GlobalMutex); sLock->Lock(); //.... sLock->Unlock(); //... delete sLock; //....... Additional query words: 4.10 ====================================================================== Keywords : kbMFC kbThread kbVC410 kbGrpDSMFCATL Technology : kbAudDeveloper kbMFC Version : winnt:4.1 Issue type : kbprb ============================================================================= 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. Copyright Microsoft Corporation 2001.