/[svn]/linuxsampler/trunk/src/common/Condition.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/common/Condition.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3290 - (hide annotations) (download) (as text)
Fri Jun 23 12:24:58 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 8711 byte(s)
* Revised fundamental C++ classes "Thread", "Mutex" and
  "Condition" which fixes potential undefined behavior
  (note: this addresses mainly the POSIX implementation,
   Win32 is untested yet and would also need an update).
* Bumped version (2.0.0.svn64).

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3290 * Copyright (C) 2005 - 2017 Christian Schoenebeck *
7 schoenebeck 53 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #ifndef __CONDITION_H__
25     #define __CONDITION_H__
26    
27     #include "Mutex.h"
28    
29 senoner 1481 #if defined(WIN32)
30     #include <windows.h>
31 schoenebeck 1560 #endif
32 senoner 1481
33 schoenebeck 1560 namespace LinuxSampler {
34 senoner 1481
35 schoenebeck 1560 #if defined(WIN32)
36     class ConditionInternal;
37 senoner 1481 #endif
38    
39 schoenebeck 53 /**
40     * Thread safe boolean condition.
41     *
42     * This is not meant to be used for real time operation!
43     */
44     class Condition : public Mutex {
45     public:
46 schoenebeck 3290 /** @brief Constructor
47 schoenebeck 53 *
48 schoenebeck 3290 * Creates a new thread safe condition variable.
49     *
50     * Note that the default bahavior of the underlying mutex is
51     * @c NON_RECURSIVE by default, because in general if your design
52     * requires the Condition object's lock state to be recursive instead,
53     * then most probably this may result in dead locks or even undefined
54     * behavior, because the underlying OS API for conditions may not be
55     * compatible with recursive mutexes!
56     *
57 schoenebeck 53 * @param bInitialCondition - optional: starting condition
58     * (default = false)
59 schoenebeck 3290 * @param mutexType - optional: fundamental behavior of underlying mutex
60     * (default: @c NON_RECURSIVE)
61 schoenebeck 53 */
62 schoenebeck 3290 Condition(bool bInitialCondition = false, Mutex::type_t mutexType = Mutex::NON_RECURSIVE);
63 schoenebeck 53
64     /**
65     * Destructor
66     */
67 letz 502 virtual ~Condition();
68 schoenebeck 53
69     /**
70     * Blocks the calling thread if current condition equals
71     * \a bCondition, in this case the calling thread will be blocked
72     * until condition turns. Upon successful return the Condition
73     * object is locked, so the calling thread can safely run it's
74     * critical section and has to explicitly call Unlock() right after
75     * it left it's critcal section.
76     *
77 schoenebeck 1221 * @e Note: If you don't provide a timeout value or if you provide a
78     * timeout value of exactly 0s and 0ns, then this call will block
79 schoenebeck 1319 * without any timeout, or in other words: @e infinity!
80 schoenebeck 1221 *
81 schoenebeck 53 * @param bCondition - block in case of this condition
82     * @param TimeoutSeconds - optional: max. wait time in seconds
83     * (default: 0s)
84     * @param TimeoutNanoSeconds - optional: max wait time in nano
85     * seconds (default: 0ns)
86     * @returns 0 on success, a value less than 0 if timeout exceeded
87     */
88     int WaitIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L);
89    
90     /**
91     * Same as WaitIf(), except that WaitAndUnlockIf() will unlock the
92     * Condition object, so only use this call if you don't need to
93     * enter a thread critical section, otherwise use WaitIf() instead!
94     *
95 schoenebeck 1221 * @e Note: If you don't provide a timeout value or if you provide a
96     * timeout value of exactly 0s and 0ns, then this call will block
97 schoenebeck 1319 * without any timeout, or in other words: @e infinity!
98 schoenebeck 1221 *
99 schoenebeck 53 * @param bCondition - block in case of this condition
100     * @param TimeoutSeconds - optional: max. wait time in seconds
101     * (default: 0s)
102     * @param TimeoutNanoSeconds - optional: max wait time in nano
103     * seconds (default: 0ns)
104     * @returns 0 on success, a value less than 0 if timeout exceeded
105     * @see WaitIf()
106     */
107     int WaitAndUnlockIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L);
108    
109     /**
110 schoenebeck 3290 * You should use this method instead of WaitIf() in case the calling
111     * thread already owns the Condition object's underlying mutex lock by
112     * previously calling Lock() before. Essentially the only difference to
113     * WaitIf() is that PreLockedWaitIf() does not call Lock() by itself.
114     */
115     int PreLockedWaitIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L);
116    
117     /**
118     * You should use this method instead of WaitAndUnlockIf() in case the
119     * calling thread already owns the Condition object's underlying mutex
120     * lock by previously calling Lock() before. Essentially the only
121     * difference to WaitAndUnlockIf() is that PreLockedWaitAndUnlockIf()
122     * does not call Lock() by itself.
123     */
124     int PreLockedWaitAndUnlockIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L);
125    
126     /**
127 schoenebeck 53 * Set Condition object to \a bCondition. Upon change of the
128     * condition, other threads waiting for \a bCondition will be
129 schoenebeck 63 * awakened. (Note the condition will not be locked for the calling
130     * thread after this method returns!)
131 schoenebeck 53 *
132     * @param bCondition - new condition
133     */
134     void Set(bool bCondition);
135    
136 schoenebeck 1221 /**
137 schoenebeck 3290 * You should use this method instead of Set() in case the calling
138     * thread already owns the Condition object's underlying mutex lock by
139     * previously calling Lock() before. Essentially the only difference to
140     * Set() is that PreLockedSet() does not call Lock() by itself.
141     */
142     void PreLockedSet(bool bCondition);
143    
144     /**
145 schoenebeck 1319 * Returns the current boolean state of this condition object. This
146     * method never blocks, it returns immediately and doesn't use any
147     * system calls.
148     *
149 schoenebeck 1231 * @e Caution: this method is not thread safe! If you need to use
150     * the condition state in a thread critical context you must call
151     * @c Lock() and @c Unlock() respectively by yourself!
152     */
153 schoenebeck 1221 bool GetUnsafe();
154    
155 persson 2316 #ifdef WIN32
156     /**
157     * Resets the condition. This is only needed on Windows, after
158     * a thread waiting for a condition has been stopped with
159     * StopThread.
160     */
161     void Reset();
162     #endif
163    
164 schoenebeck 53 protected:
165 schoenebeck 3290 int WaitIfInternal(bool bLock, bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds);
166     void SetInternal(bool bLock, bool bCondition);
167    
168 senoner 1481 #if defined(WIN32)
169 schoenebeck 1560 friend class ConditionInternal;
170     struct win32thread_cond_t {
171     int waiters_count_; ///< Number of waiting threads.
172     CRITICAL_SECTION waiters_count_lock_; ///< Serialize access to <waiters_count_>.
173     HANDLE sema_; ///< Semaphore used to queue up threads waiting for the condition to become signaled.
174     HANDLE waiters_done_; ///< An auto-reset event used by the broadcast/signal thread to wait for all the waiting thread(s) to wake up and be released from the semaphore.
175     size_t was_broadcast_; ///< Keeps track of whether we were broadcasting or signaling. This allows us to optimize the code if we're just signaling.
176     } __win32_true_condition, __win32_false_condition;
177 senoner 1481 #else
178 schoenebeck 53 pthread_cond_t __posix_true_condition;
179     pthread_cond_t __posix_false_condition;
180 senoner 1481 #endif
181 schoenebeck 53 bool bCondition;
182     };
183    
184 schoenebeck 880 } // namespace LinuxSampler
185    
186 schoenebeck 53 #endif // __CONDITION_H__

  ViewVC Help
Powered by ViewVC