Guest User

simple condition-variable for Win32/C++

a guest
May 18th, 2016
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.28 KB | None | 0 0
  1. #include <windows.h>
  2. #include <cassert>
  3. #include <exception>
  4.  
  5. #if !defined(NDEBUG)
  6.     #define ONDEBUG(expr) (expr)
  7. #else
  8.     #define ONDEBUG(expr) ((void)0)
  9. #endif
  10.  
  11. class Exception : public std::exception
  12. {
  13. };
  14.  
  15. class ResourceException : Exception
  16. {
  17. };
  18.  
  19. template <typename TYPE>
  20. inline
  21. TYPE AutoThrowResourceException( TYPE t )
  22. {
  23.     if( !t )
  24.         throw ResourceException();
  25.  
  26.     return t;
  27. }
  28.  
  29. class XHANDLE
  30. {
  31. public:
  32.          XHANDLE( HANDLE h = NULL );
  33.          XHANDLE();
  34.          ~XHANDLE();
  35.     void CloseHandle();
  36.  
  37. public:
  38.     HANDLE h;
  39. };
  40.  
  41. inline
  42. XHANDLE::XHANDLE( HANDLE h )
  43. {
  44.     this->h = h;
  45. }
  46.  
  47. inline
  48. XHANDLE::~XHANDLE()
  49. {
  50.     BOOL fClosed;
  51.  
  52.     if( h && h != INVALID_HANDLE_VALUE )
  53.         fClosed = ::CloseHandle( h ),
  54.         assert(fClosed);
  55. }
  56.  
  57. inline
  58. void XHANDLE::CloseHandle()
  59. {
  60.     ::CloseHandle( h );
  61.     h = NULL;
  62. }
  63.  
  64.  
  65. class CondVar
  66. {
  67. public:
  68.          CondVar();
  69.          ~CondVar();
  70.     void Enter();
  71.     void Wait();
  72.     void Release();
  73.     void ReleaseAll();
  74.     void Leave();
  75.  
  76. private:
  77.     union
  78.     {
  79.         LONG  volatile m_lMutex;
  80.         DWORD volatile m_dwOwnerCounter;
  81.     };
  82.     DWORD volatile    m_dwWaitingForSignal;
  83. #if !defined(NDEBUG)
  84.     DWORD volatile    m_dwOwningThreadId;
  85. #endif
  86.     XHANDLE           m_xhEvtEnter,
  87.                       m_xhSemRelease;
  88. };
  89.  
  90.  
  91. CondVar::CondVar() :
  92.     m_xhEvtEnter(   AutoThrowResourceException( ::CreateEvent( NULL, FALSE, FALSE, NULL ) ) ),
  93.     m_xhSemRelease( AutoThrowResourceException( ::CreateSemaphore( NULL, 0, 0x7FFFFFFF, NULL ) ) )
  94. {
  95.     ONDEBUG(m_dwOwningThreadId = 0);
  96.  
  97.     m_lMutex             = 0;
  98.     m_dwWaitingForSignal = 0;
  99. }
  100.  
  101. CondVar::~CondVar()
  102. {
  103. }
  104.  
  105. void CondVar::Enter()
  106. {
  107.     LONG lMutex,
  108.          lMtxPrevOrChanged;
  109.  
  110.     for( lMutex = m_lMutex; ; lMutex = lMtxPrevOrChanged )
  111.         if( (lMtxPrevOrChanged = ::InterlockedCompareExchange( &m_lMutex, lMutex + 1, lMutex )) != lMutex )
  112.             continue;
  113.  
  114.     if( lMutex != 0 )
  115.     {
  116.         for( ; ::WaitForSingleObject( m_xhEvtEnter.h, INFINITE ) != WAIT_OBJECT_0; assert(false) );
  117.         assert(m_lMutex != 0);
  118.     }
  119.  
  120.     ONDEBUG(m_dwOwningThreadId = GetCurrentThreadId());
  121. }
  122.  
  123. void CondVar::Wait()
  124. {
  125.     DWORD dwOwnerCounter     = (DWORD)m_dwOwnerCounter,
  126.           dwWaitingForSignal = ++m_dwWaitingForSignal;
  127.  
  128.     assert(dwOwnerCounter >= dwWaitingForSignal);
  129.     assert(m_dwOwningThreadId == GetCurrentThreadId());
  130.     ONDEBUG(m_dwOwningThreadId = 0);
  131.  
  132.     if( dwOwnerCounter > dwWaitingForSignal )
  133.         for( ; !::SetEvent( m_xhEvtEnter.h ); assert(false) );
  134.  
  135.     HANDLE ahWait[2] = { m_xhEvtEnter.h, m_xhSemRelease.h };
  136.  
  137.     for( ; ::WaitForMultipleObjects( 2, ahWait, TRUE, INFINITE ) != WAIT_OBJECT_0; assert(false) );
  138.     assert(m_dwOwnerCounter > m_dwWaitingForSignal);
  139.     ONDEBUG(m_dwOwningThreadId = GetCurrentThreadId());
  140. }
  141.  
  142. void CondVar::Release()
  143. {
  144.     assert(m_dwOwnerCounter > m_dwWaitingForSignal && m_dwOwningThreadId == GetCurrentThreadId());
  145.  
  146.     if( m_dwWaitingForSignal != 0 )
  147.     {
  148.         m_dwWaitingForSignal--;
  149.         for( ; !::ReleaseSemaphore( m_xhSemRelease.h, 1, NULL ); assert(false) );
  150.     }
  151. }
  152.  
  153. void CondVar::ReleaseAll()
  154. {
  155.     DWORD dwWaitingForSignal;
  156.  
  157.     assert(m_dwOwnerCounter > m_dwWaitingForSignal && m_dwOwningThreadId == GetCurrentThreadId());
  158.  
  159.     if( (dwWaitingForSignal = m_dwWaitingForSignal) != 0 )
  160.     {
  161.         m_dwWaitingForSignal = 0;
  162.         for( ; !::ReleaseSemaphore( m_xhSemRelease.h, (LONG)dwWaitingForSignal, NULL ); assert(false) );
  163.     }
  164. }
  165.  
  166. void CondVar::Leave()
  167. {
  168.     LONG  lMutex,
  169.           lMtxPrevOrChanged;
  170.     DWORD dwOwnerCounter,
  171.           dwWaitingForSignal;
  172.  
  173.     assert(m_dwOwnerCounter > m_dwWaitingForSignal && m_dwOwningThreadId == GetCurrentThreadId());
  174.     ONDEBUG(m_dwOwningThreadId = 0);
  175.  
  176.     for( lMutex = m_lMutex; ; lMutex = lMtxPrevOrChanged )
  177.     {
  178.         dwOwnerCounter     = (DWORD)lMutex,
  179.         dwWaitingForSignal = m_dwWaitingForSignal;
  180.  
  181.         assert(dwOwnerCounter > dwWaitingForSignal);
  182.  
  183.         if( (lMtxPrevOrChanged = ::InterlockedCompareExchange( &m_lMutex, (LONG)--dwOwnerCounter, lMutex )) == lMutex )
  184.             break;
  185.     }
  186.  
  187.     if( dwOwnerCounter > dwWaitingForSignal )
  188.         for( ; !::SetEvent( m_xhEvtEnter.h ); assert(false) );
  189. }
Advertisement
Add Comment
Please, Sign In to add comment