File: itkConditionVariable.cxx

package info (click to toggle)
insighttoolkit 3.6.0-3
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 94,956 kB
  • ctags: 74,981
  • sloc: cpp: 355,621; ansic: 195,070; fortran: 28,713; python: 3,802; tcl: 1,996; sh: 1,175; java: 583; makefile: 415; csh: 184; perl: 175
file content (165 lines) | stat: -rwxr-xr-x 4,878 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkConditionVariable.cxx,v $
  Language:  C++
  Date:      $Date: 2006-03-18 20:14:38 $
  Version:   $Revision: 1.8 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "itkConditionVariable.h"

namespace itk {
  
ConditionVariable::ConditionVariable()
{
#ifdef ITK_USE_PTHREADS
  pthread_mutex_init(&m_Mutex, NULL);
  pthread_cond_init(&m_ConditionVariable, NULL);
#else
#ifdef WIN32
  m_NumberOfWaiters = 0;
  m_WasBroadcast = 0;
  m_Semaphore = CreateSemaphore(NULL,         // no security
                                0,            // initial value
                                0x7fffffff,   // max count
                                NULL);        // unnamed
  InitializeCriticalSection( &m_NumberOfWaitersLock );
  m_WaitersAreDone = CreateEvent( NULL,           // no security
                                  FALSE,          // auto-reset
                                  FALSE,          // non-signaled initially
                                  NULL );         // unnamed
#endif
#endif
}

ConditionVariable::~ConditionVariable()
{
#ifdef ITK_USE_PTHREADS
  pthread_mutex_destroy(&m_Mutex);
  pthread_cond_destroy(&m_ConditionVariable);
#else
#ifdef WIN32
  CloseHandle( m_Semaphore );
  CloseHandle( m_WaitersAreDone );
  DeleteCriticalSection( &m_NumberOfWaitersLock );
#endif
#endif
  
}

void ConditionVariable::Signal()  
{
#ifdef ITK_USE_PTHREADS
  pthread_cond_signal(&m_ConditionVariable);
#else
#ifdef WIN32
  EnterCriticalSection( &m_NumberOfWaitersLock );
  int haveWaiters = m_NumberOfWaiters > 0;
  LeaveCriticalSection( &m_NumberOfWaitersLock );

  // if there were not any waiters, then this is a no-op
  if (haveWaiters)
    {
    ReleaseSemaphore(m_Semaphore, 1, 0);
    }
#endif
#endif
}

void ConditionVariable::Broadcast()
{
#ifdef ITK_USE_PTHREADS
  pthread_cond_broadcast(&m_ConditionVariable);
#else
#ifdef WIN32
  // This is needed to ensure that m_NumberOfWaiters and m_WasBroadcast are
  // consistent
  EnterCriticalSection( &m_NumberOfWaitersLock );
  int haveWaiters = 0;

  if (m_NumberOfWaiters > 0)
    {
    // We are broadcasting, even if there is just one waiter...
    // Record that we are broadcasting, which helps optimize Wait()
    // for the non-broadcast case
    m_WasBroadcast = 1;
    haveWaiters = 1;
    }

  if (haveWaiters)
    {
    // Wake up all waiters atomically
    ReleaseSemaphore(m_Semaphore, m_NumberOfWaiters, 0);

    LeaveCriticalSection( &m_NumberOfWaitersLock );

    // Wait for all the awakened threads to acquire the counting
    // semaphore
    WaitForSingleObject( m_WaitersAreDone, INFINITE );
    // This assignment is ok, even without the m_NumberOfWaitersLock held
    // because no other waiter threads can wake up to access it.
    m_WasBroadcast = 0;
    }
  else
    {
    LeaveCriticalSection( &m_NumberOfWaitersLock );
    }
#endif
#endif
}

void ConditionVariable::Wait(SimpleMutexLock *mutex)
{
#ifdef ITK_USE_PTHREADS
  pthread_cond_wait(&m_ConditionVariable, &mutex->GetMutexLock() );
#else
#ifdef WIN32
  // Avoid race conditions
  EnterCriticalSection( &m_NumberOfWaitersLock );
  m_NumberOfWaiters++;
  LeaveCriticalSection( &m_NumberOfWaitersLock );

  // This call atomically releases the mutex and waits on the
  // semaphore until signaled
  SignalObjectAndWait( mutex->GetMutexLock(), m_Semaphore, INFINITE, FALSE );

  // Reacquire lock to avoid race conditions
  EnterCriticalSection( &m_NumberOfWaitersLock );

  // We're no longer waiting....
  m_NumberOfWaiters--;

  // Check to see if we're the last waiter after the broadcast
  int lastWaiter = m_WasBroadcast && m_NumberOfWaiters == 0;

  LeaveCriticalSection( &m_NumberOfWaitersLock );

  // If we're the last waiter thread during this particular broadcast
  // then let the other threads proceed
  if (lastWaiter)
    {
    // This call atomically signals the m_WaitersAreDone event and waits
    // until it can acquire the external mutex.  This is required to
    // ensure fairness
    SignalObjectAndWait( m_WaitersAreDone, mutex->GetMutexLock(), 
                                                             INFINITE, FALSE);
    }
  else
    {
    // Always regain the external mutex since that's the guarentee we
    // give to our callers
    WaitForSingleObject( mutex->GetMutexLock(), INFINITE );
    }
#endif
#endif
}

}//end of namespace itk