Logo ROOT   6.10/09
Reference Guide
TWin32Condition.cxx
Go to the documentation of this file.
1 // @(#)root/thread:$Id$
2 // Author: Bertrand Bellenot 20/10/2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TWin32Condition //
15 // //
16 // This class provides an interface to the win32 condition variable //
17 // routines. //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include "TWin32Condition.h"
22 #include "TWin32Mutex.h"
23 #include "TTimeStamp.h"
24 #include "Windows4Root.h"
25 
26 #include <errno.h>
27 
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 /// Create Condition variable. Ctor must be given a pointer to an
32 /// existing mutex. The condition variable is then linked to the mutex,
33 /// so that there is an implicit unlock and lock around Wait() and
34 /// TimedWait().
35 
37 {
38  fMutex = (TWin32Mutex *) m;
39 
40  fCond.waiters_count_ = 0;
41  fCond.was_broadcast_ = 0;
42  fCond.sema_ = CreateSemaphore(0, // no security
43  0, // initially 0
44  0x7fffffff, // max count
45  0); // unnamed
46  InitializeCriticalSection (&fCond.waiters_count_lock_);
47  fCond.waiters_done_ = CreateEvent(0, // no security
48  FALSE, // auto-reset
49  FALSE, // non-signaled initially
50  0); // unnamed
51 }
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// TCondition dtor.
55 
57 {
58 }
59 
60 ////////////////////////////////////////////////////////////////////////////////
61 /// Wait for the condition variable to be signalled. The mutex is
62 /// implicitely released before waiting and locked again after waking up.
63 /// If Wait() is called by multiple threads, a signal may wake up more
64 /// than one thread. See POSIX threads documentation for details.
65 
67 {
68  // Avoid race conditions.
69  EnterCriticalSection(&fCond.waiters_count_lock_);
71  LeaveCriticalSection(&fCond.waiters_count_lock_);
72 
73  // This call atomically releases the mutex and waits on the
74  // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
75  // are called by another thread.
76  // SignalObjectAndWait(fMutex->fHMutex, fCond.sema_, INFINITE, FALSE);
77  ::LeaveCriticalSection(&fMutex->fCritSect);
78  WaitForSingleObject(fCond.sema_, INFINITE);
79 
80  // Reacquire lock to avoid race conditions.
81  EnterCriticalSection(&fCond.waiters_count_lock_);
82 
83  // We're no longer waiting...
85 
86  // Check to see if we're the last waiter after <pthread_cond_broadcast>.
87  int last_waiter = fCond.was_broadcast_ && fCond.waiters_count_ == 0;
88 
89  LeaveCriticalSection(&fCond.waiters_count_lock_);
90 
91  // If we're the last waiter thread during this particular broadcast
92  // then let all the other threads proceed.
93  if (last_waiter) {
94  // This call atomically signals the <waiters_done_> event and waits until
95  // it can acquire the <fMutex->fHMutex>. This is required to ensure fairness.
96  // SignalObjectAndWait(fCond.waiters_done_, fMutex->fHMutex, INFINITE, FALSE);
97  SetEvent(fCond.waiters_done_);
98  ::EnterCriticalSection(&fMutex->fCritSect);
99  }
100  else
101  // Always regain the external mutex since that's the guarantee we
102  // give to our callers.
103  // WaitForSingleObject(fMutex->fHMutex, INFINITE);
104  ::EnterCriticalSection(&fMutex->fCritSect);
105 
106  return 0;
107 }
108 
109 ////////////////////////////////////////////////////////////////////////////////
110 /// TimedWait() is given an absolute time to wait until. To wait for a
111 /// relative time from now, use TThread::GetTime(). See POSIX threads
112 /// documentation for why absolute times are better than relative.
113 /// Returns 0 if successfully signalled, 1 if time expired.
114 
116 {
117  DWORD ret;
118  TTimeStamp t;
119  // Get actual time
120  ULong_t secNow = t.GetSec();
121  ULong_t nanosecNow = t.GetNanoSec();
122  DWORD dwMillisecondsNow = (DWORD)((secNow * 1000) + (nanosecNow / 1000000));
123  DWORD dwMilliseconds = (DWORD)((secs * 1000) + (nanoSecs / 1000000));
124  // Calculate delta T to obtain the real time to wait for
125  DWORD dwTimeWait = (DWORD)(dwMilliseconds - dwMillisecondsNow);
126  // Avoid race conditions.
127  EnterCriticalSection(&fCond.waiters_count_lock_);
129  LeaveCriticalSection(&fCond.waiters_count_lock_);
130 
131  // This call atomically releases the mutex and waits on the
132  // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
133  // are called by another thread.
134  // ret = SignalObjectAndWait(fMutex->fHMutex, fCond.sema_, dwTimeWait, FALSE);
135  ::LeaveCriticalSection(&fMutex->fCritSect);
136  ret = WaitForSingleObject(fCond.sema_, dwTimeWait);
137 
138  // Reacquire lock to avoid race conditions.
139  EnterCriticalSection(&fCond.waiters_count_lock_);
140 
141  // We're no longer waiting...
143 
144  // Check to see if we're the last waiter after <pthread_cond_broadcast>.
145  int last_waiter = fCond.was_broadcast_ && fCond.waiters_count_ == 0;
146 
147  LeaveCriticalSection(&fCond.waiters_count_lock_);
148 
149  // If we're the last waiter thread during this particular broadcast
150  // then let all the other threads proceed.
151  if (last_waiter) {
152  // This call atomically signals the <waiters_done_> event and waits until
153  // it can acquire the <fMutex->fHMutex>. This is required to ensure fairness.
154  // SignalObjectAndWait(fCond.waiters_done_, fMutex->fHMutex, dwTimeWait, FALSE);
155  SetEvent(fCond.waiters_done_);
156  ::EnterCriticalSection(&fMutex->fCritSect);
157  }
158  else
159  // Always regain the external mutex since that's the guarantee we
160  // give to our callers.
161  // WaitForSingleObject(fMutex->fHMutex, INFINITE);
162  ::EnterCriticalSection(&fMutex->fCritSect);
163 
164  if (ret == WAIT_TIMEOUT)
165  return 1;
166  return 0;
167 }
168 
169 ////////////////////////////////////////////////////////////////////////////////
170 /// If one or more threads have called Wait(), Signal() wakes up at least
171 /// one of them, possibly more. See POSIX threads documentation for details.
172 
174 {
175  EnterCriticalSection (&fCond.waiters_count_lock_);
176  int have_waiters = fCond.waiters_count_ > 0;
177  LeaveCriticalSection (&fCond.waiters_count_lock_);
178 
179  // If there aren't any waiters, then this is a no-op.
180  if (have_waiters)
181  ReleaseSemaphore(fCond.sema_, 1, 0);
182 
183  return 0;
184 }
185 
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Broadcast is like signal but wakes all threads which have called Wait().
189 
191 {
192  // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
193  // consistent relative to each other.
194  EnterCriticalSection(&fCond.waiters_count_lock_);
195  int have_waiters = 0;
196 
197  if (fCond.waiters_count_ > 0) {
198  // We are broadcasting, even if there is just one waiter...
199  // Record that we are broadcasting, which helps optimize
200  // <pthread_cond_wait> for the non-broadcast case.
201  fCond.was_broadcast_ = 1;
202  have_waiters = 1;
203  }
204 
205  if (have_waiters) {
206  // Wake up all the waiters atomically.
207  ReleaseSemaphore(fCond.sema_, fCond.waiters_count_, 0);
208 
209  LeaveCriticalSection(&fCond.waiters_count_lock_);
210 
211  // Wait for all the awakened threads to acquire the counting
212  // semaphore.
213  WaitForSingleObject(fCond.waiters_done_, INFINITE);
214  // This assignment is okay, even without the <waiters_count_lock_> held
215  // because no other waiter threads can wake up to access it.
216  fCond.was_broadcast_ = 0;
217  }
218  else
219  LeaveCriticalSection(&fCond.waiters_count_lock_);
220 
221  return 0;
222 }
Int_t TimedWait(ULong_t secs, ULong_t nanoSecs=0)
TimedWait() is given an absolute time to wait until.
Int_t Wait()
Wait for the condition variable to be signalled.
int Int_t
Definition: RtypesCore.h:41
time_t GetSec() const
Definition: TTimeStamp.h:135
CRITICAL_SECTION fCritSect
Definition: TWin32Mutex.h:37
pthread_cond_t fCond
TMarker * m
Definition: textangle.C:8
virtual ~TWin32Condition()
TCondition dtor.
#define ClassImp(name)
Definition: Rtypes.h:336
Int_t Signal()
If one or more threads have called Wait(), Signal() wakes up at least one of them, possibly more.
unsigned long ULong_t
Definition: RtypesCore.h:51
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:71
#define FALSE
Int_t GetNanoSec() const
Definition: TTimeStamp.h:136
TWin32Mutex * fMutex
Int_t Broadcast()
Broadcast is like signal but wakes all threads which have called Wait().
CRITICAL_SECTION waiters_count_lock_