Logo ROOT   6.16/01
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
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.
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.
217 }
218 else
219 LeaveCriticalSection(&fCond.waiters_count_lock_);
220
221 return 0;
222}
int Int_t
Definition: RtypesCore.h:41
unsigned long ULong_t
Definition: RtypesCore.h:51
#define ClassImp(name)
Definition: Rtypes.h:363
#define FALSE
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:71
time_t GetSec() const
Definition: TTimeStamp.h:135
Int_t GetNanoSec() const
Definition: TTimeStamp.h:136
Int_t Wait()
Wait for the condition variable to be signalled.
pthread_cond_t fCond
virtual ~TWin32Condition()
TCondition dtor.
Int_t Broadcast()
Broadcast is like signal but wakes all threads which have called Wait().
TWin32Condition(TMutexImp *m)
Create Condition variable.
TWin32Mutex * fMutex
Int_t TimedWait(ULong_t secs, ULong_t nanoSecs=0)
TimedWait() is given an absolute time to wait until.
Int_t Signal()
If one or more threads have called Wait(), Signal() wakes up at least one of them,...
CRITICAL_SECTION fCritSect
Definition: TWin32Mutex.h:37
CRITICAL_SECTION waiters_count_lock_
auto * m
Definition: textangle.C:8