Forward compatibility: flex
[foam-extend-3.2.git] / src / OSspecific / POSIX / multiThreader / threadHandlerI.H
blob6642ec734e45f397153f2437911d3fd80aa33d48
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
28 namespace Foam
31 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
33 // Constructor for threadHandler
34 template<class T>
35 threadHandler<T>::threadHandler
37     T& tRef,
38     const multiThreader& threader
41     tRef_(tRef),
42     threader_(threader),
43     argList_(0),
44     nThreads_(threader.getNumThreads()),
45     pthreadID_(pthread_self()),
46     master_(false),
47     predicate_(false)
51 // * * * * * * * * * * * * * * * *  Destructors  * * * * * * * * * * * * * * //
53 template<class T>
54 threadHandler<T>::~threadHandler()
56     // Null the argument list pointer copies
57     // to avoid multiple deallocations.
58     forAll(argList_, indexI)
59     {
60         argList_[indexI] = NULL;
61     }
65 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
67 // Return a reference to the template class
68 template<class T>
69 inline T& threadHandler<T>::reference()
71     return tRef_;
75 // Set a size for the argument list
76 template<class T>
77 inline void threadHandler<T>::setSize
79     const label size
82     argList_.setSize(size, NULL);
86 // Set a argument pointer for a particular index
87 template<class T>
88 inline void threadHandler<T>::set
90     const label index,
91     void* argPtr
94     if (!argList_.size())
95     {
96         FatalErrorIn("threadHandler<T>::set")
97             << "Attempt to access element from zero sized list"
98             << abort(FatalError);
99     }
100     else
101     if (index < 0 || index >= argList_.size())
102     {
103         FatalErrorIn("threadHandler<T>::set")
104             << "index " << index << " out of range 0 ... "
105             << argList_.size()-1
106             << abort(FatalError);
107     }
109     argList_[index] = argPtr;
113 // Return a reference to the multiThreader
114 template<class T>
115 inline const multiThreader& threadHandler<T>::threader() const
117     return threader_;
121 // Return the number of threads
122 template<class T>
123 inline label threadHandler<T>::nThreads() const
125     return nThreads_;
129 // Designate as master thread
130 template<class T>
131 inline void threadHandler<T>::setMaster() const
133     master_ = true;
137 // Designate as slave thread
138 template<class T>
139 inline void threadHandler<T>::setSlave() const
141     master_ = false;
145 // Is this a master thread?
146 template<class T>
147 inline bool threadHandler<T>::master() const
149     return (master_ == true);
153 // Is this a slave thread?
154 template<class T>
155 inline bool threadHandler<T>::slave() const
157     return !master();
161 // Lock this thread
162 template<class T>
163 inline void threadHandler<T>::lock
165     const signalType sType
166 ) const
168     if (sType == START)
169     {
170         startMutex_.lock();
171     }
172     else
173     if (sType == STOP)
174     {
175         stopMutex_.lock();
176     }
180 // Unlock this thread
181 template<class T>
182 inline void threadHandler<T>::unlock
184     const signalType sType
185 ) const
187     if (sType == START)
188     {
189         startMutex_.unlock();
190     }
191     else
192     if (sType == STOP)
193     {
194         stopMutex_.unlock();
195     }
199 // Send signal to a waiting conditional
200 template<class T>
201 inline void threadHandler<T>::sendSignal
203     const signalType sType
204 ) const
206     lock(sType);
208     if (predicate(sType))
209     {
210         InfoIn("threadHandler::sendSignal()")
211             << "Predicate is already set."
212             << endl;
213     }
214     else
215     {
216         // Set predicate before signalling
217         setPredicate(sType);
218     }
220     if (sType == START)
221     {
222         threader().signal
223         (
224             startConditional_
225         );
226     }
227     else
228     if (sType == STOP)
229     {
230         threader().signal
231         (
232             stopConditional_
233         );
234     }
235     else
236     {
237         FatalErrorIn("threadHandler::sendSignal()")
238             << "Undefined enumerant."
239             << abort(FatalError);
240     }
242     unlock(sType);
246 // Wait for signal
247 template<class T>
248 inline void threadHandler<T>::waitForSignal
250     const signalType sType
251 ) const
253     if (sType == START)
254     {
255         threader().waitForCondition
256         (
257             startConditional_,
258             startMutex_
259         );
260     }
261     else
262     if (sType == STOP)
263     {
264         threader().waitForCondition
265         (
266             stopConditional_,
267             stopMutex_
268         );
269     }
270     else
271     {
272         FatalErrorIn("threadHandler::waitForSignal()")
273             << "Undefined enumerant."
274             << abort(FatalError);
275     }
277     if (!predicate(sType))
278     {
279         FatalErrorIn("threadHandler::waitForSignal()")
280             << "Spurious wake-up."
281             << abort(FatalError);
282     }
284     unsetPredicate(sType);
286     // Unlock the acquired mutex
287     unlock(sType);
291 // Return state of the predicate variable
292 template<class T>
293 inline bool threadHandler<T>::predicate
295     const signalType sType
296 ) const
298     return predicate_[sType];
302 // Set the predicate variable
303 template<class T>
304 inline void threadHandler<T>::setPredicate
306     const signalType sType
307 ) const
309     predicate_[sType] = true;
313 // Unset the predicate variable
314 template<class T>
315 inline void threadHandler<T>::unsetPredicate
317     const signalType sType
318 ) const
320     predicate_[sType] = false;
324 // Return the ID
325 template<class T>
326 inline void threadHandler<T>::setID(const pthread_t& pt)
328     pthreadID_ = pt;
332 // Return the ID
333 template<class T>
334 inline pthread_t threadHandler<T>::ID() const
336     return pthreadID_;
340 // Does the calling thread correspond to this handler?
341 template<class T>
342 inline bool threadHandler<T>::self() const
344     return pthread_equal(ID(), pthread_self());
348 // Return an argument pointer at a particular index
349 template<class T>
350 inline void * threadHandler<T>::operator()
352     const label index
355     if (!argList_.size())
356     {
357         FatalErrorIn("threadHandler<T>::operator()")
358             << "Attempt to access element from zero sized list"
359             << abort(FatalError);
360     }
361     else
362     if (index < 0 || index >= argList_.size())
363     {
364         FatalErrorIn("threadHandler<T>::operator()")
365             << "index " << index << " out of range 0 ... "
366             << argList_.size()-1
367             << abort(FatalError);
368     }
369     else
370     if (!argList_[index])
371     {
372         FatalErrorIn("threadHandler<T>::operator()")
373             << "Hanging pointer. This is not allowed."
374             << abort(FatalError);
375     }
377     return argList_[index];
381 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
383 // Lock all threads provided by sequence
384 template <class T>
385 void lockThreads
387     const List<label>& sequence,
388     const PtrList<threadHandler<T> >& handler
391     forAll(sequence, i)
392     {
393         handler[sequence[i]].lock(threadHandler<T>::START);
394         handler[sequence[i]].lock(threadHandler<T>::STOP);
396         handler[sequence[i]].unsetPredicate(threadHandler<T>::START);
397         handler[sequence[i]].unsetPredicate(threadHandler<T>::STOP);
398     }
402 // Synchronize all threads provided by sequence
403 template <class T>
404 void synchronizeThreads
406     const List<label>& sequence,
407     const PtrList<threadHandler<T> >& handler
410     forAll(sequence, i)
411     {
412         // Wait for a signal from this thread before moving on.
413         handler[sequence[i]].waitForSignal(threadHandler<T>::STOP);
414     }
418 // Execute threads for the submitted static function by sequence
419 template <class T>
420 void executeThreads
422     const List<label>& sequence,
423     PtrList<threadHandler<T> >& handler,
424     void (*tFunction)(void*)
427     if (!handler.size())
428     {
429         FatalErrorIn
430         (
431             "\n\n"
432             "template <class T>\n"
433             "void executeThreads\n"
434             "(\n"
435             "    const List<label>& sequence,\n"
436             "    PtrList<threadHandler<T> >& handler,\n"
437             "    void (*tFunction)(void*)\n"
438             ")\n"
439         )
440             << "Empty handler list."
441             << abort(FatalError);
442     }
444     // Fetch threader reference
445     const multiThreader& threader = handler[0].threader();
447     // Lock slave threads by sequence
448     lockThreads(sequence, handler);
450     forAll(sequence, i)
451     {
452         // Submit jobs to the work queue
453         threader.addToWorkQueue(tFunction, &(handler[sequence[i]]));
455         // Wait for a signal from this thread before moving on.
456         handler[sequence[i]].waitForSignal(threadHandler<T>::START);
457     }
459     // Synchronize threads
460     synchronizeThreads(sequence, handler);
463 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
465 } // End namespace Foam
467 // ************************************************************************* //