Line data Source code
1 : // Copyright (c) 2013-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/cppthread
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Implementation of the Thread Runner and Managers.
22 : *
23 : * This file includes the implementation used by the cppthread environment.
24 : */
25 :
26 :
27 : // self
28 : //
29 : #include "cppthread/mutex.h"
30 :
31 : #include "cppthread/exception.h"
32 : #include "cppthread/guard.h"
33 : #include "cppthread/log.h"
34 :
35 :
36 : // C lib
37 : //
38 : #include <string.h>
39 : #include <sys/time.h>
40 :
41 :
42 : // last include
43 : //
44 : #include <snapdev/poison.h>
45 :
46 :
47 :
48 :
49 : namespace cppthread
50 : {
51 :
52 :
53 :
54 : namespace detail
55 : {
56 :
57 :
58 :
59 : /** \brief The implementation of the mutex.
60 : *
61 : * We have an internal implementation of the mutex to avoid leaking the
62 : * pthread library to the outside.
63 : *
64 : * The class holds a mutex and a condition which we use to wait in various
65 : * circumstances such as when we pop items from a currently empty fifo.
66 : */
67 28 : class mutex_impl
68 : {
69 : public:
70 : pthread_mutex_t f_mutex = pthread_mutex_t();
71 : pthread_cond_t f_condition = pthread_cond_t();
72 : };
73 :
74 :
75 : /** \var pthread_mutex_t mutex_impl::f_mutex
76 : * \brief Mutex to support guards & signals.
77 : *
78 : * This is the actual system mutex. It is useful to protect areas of code
79 : * that only one thread is allowed to access at a time.
80 : *
81 : * The mutex also supports a condition that it can wait on and signal. This
82 : * is useful to signal a new state such as the end of FIFO as any thread
83 : * waiting on that FIFO now needs to wake up a give up (no more messages
84 : * will be sent to the FIFO).
85 : */
86 :
87 :
88 : /** \var pthread_mutex_t mutex_impl::f_condition
89 : * \brief Condition linked to the mutex to support signalling.
90 : *
91 : * We often have to signal that a thread is done in regard to something or
92 : * other. That will wake up another thread which can then take over the
93 : * next step of the work.
94 : *
95 : * The condition is used for that purpose as we can wait on it with the
96 : * attached mutex.
97 : */
98 :
99 :
100 :
101 : }
102 :
103 :
104 :
105 : /** \class mutex
106 : * \brief A mutex object to ensures atomicity.
107 : *
108 : * This class is used by threads when some data accessed by more than
109 : * one thread is about to be accessed. In most cases it is used with the
110 : * guard class so it is safe even in the event an exception is raised.
111 : *
112 : * The mutex also includes a condition variable which can be signaled
113 : * using the signal() function. This wakes threads that are currently
114 : * waiting on the condition with one of the wait() functions.
115 : *
116 : * \note
117 : * We use a recursive mutex so you may lock the mutex any number of times.
118 : * It has to be unlocked that many times, of course.
119 : */
120 :
121 :
122 :
123 :
124 : /** \brief An inter-thread mutex to ensure unicity of execution.
125 : *
126 : * The mutex object is used to lock part of the code that needs to be run
127 : * by only one thread at a time. This is also called a critical section
128 : * and a memory barrier.
129 : *
130 : * In most cases one uses the guard object to temporarily lock
131 : * the mutex using the FIFO to help ensure the mutex gets unlocked as
132 : * required in the event an exception occurs.
133 : *
134 : * \code
135 : * {
136 : * cppthread::guard lock(&my_mutex)
137 : * ... // protected code
138 : * }
139 : * \endcode
140 : *
141 : * The lock can be tried to see whether another thread already has the
142 : * lock and fail if so. See the try_lock() function.
143 : *
144 : * The class also includes a condition in order to send signals and wait
145 : * on signals. There are two ways to send signals and three ways to wait.
146 : * Note that to call any one of the wait functions you must first have the
147 : * mutex locked, what otherwise happens is undefined.
148 : *
149 : * \code
150 : * {
151 : * // wake one waiting thread
152 : * my_mutex.signal();
153 : *
154 : * // wake all the waiting thread
155 : * my_mutex.broadcast();
156 : *
157 : * // wait on the signal forever
158 : * {
159 : * cppthread::guard lock(&my_mutex);
160 : * my_mutex.wait();
161 : * }
162 : *
163 : * // wait on the signal for the specified amount of time
164 : * {
165 : * cppthread::guard lock(&my_mutex);
166 : * my_mutex.timed_wait(1000000UL); // wait up to 1 second
167 : * }
168 : *
169 : * // wait on the signal for until date or later or the signal
170 : * {
171 : * cppthread::guard lock(&my_mutex);
172 : * my_mutex.dated_wait(date); // wait on signal or until date
173 : * }
174 : * }
175 : * \endcode
176 : *
177 : * If you need a FIFO of messages between your threads, look at the
178 : * snap_fifo template.
179 : *
180 : * \note
181 : * Care must be used to always initialized a mutex before it
182 : * is possibly accessed by more than one thread. This is usually
183 : * the case in the constructor of your objects.
184 : *
185 : * \exception cppthread_exception_invalid_error
186 : * If any one of the initialization functions fails, this exception is
187 : * raised. The function also logs the error.
188 : */
189 28 : mutex::mutex()
190 28 : : f_impl(std::make_shared<detail::mutex_impl>())
191 : {
192 : // initialize the mutex
193 28 : pthread_mutexattr_t mattr;
194 28 : int err(pthread_mutexattr_init(&mattr));
195 28 : if(err != 0)
196 : {
197 0 : log << log_level_t::fatal
198 0 : << "a mutex attribute structure could not be initialized, error #"
199 0 : << err
200 0 : << end;
201 0 : throw cppthread_invalid_error("pthread_muteattr_init() failed");
202 : }
203 28 : err = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
204 28 : if(err != 0)
205 : {
206 0 : log << log_level_t::fatal
207 0 : << "a mutex attribute structure type could not be setup, error #"
208 0 : << err
209 0 : << end;
210 0 : pthread_mutexattr_destroy(&mattr);
211 0 : throw cppthread_invalid_error("pthread_muteattr_settype() failed");
212 : }
213 28 : err = pthread_mutex_init(&f_impl->f_mutex, &mattr);
214 28 : if(err != 0)
215 : {
216 0 : log << log_level_t::fatal
217 0 : << "a mutex structure could not be initialized, error #"
218 0 : << err
219 0 : << end;
220 0 : pthread_mutexattr_destroy(&mattr);
221 0 : throw cppthread_invalid_error("pthread_mutex_init() failed");
222 : }
223 28 : err = pthread_mutexattr_destroy(&mattr);
224 28 : if(err != 0)
225 : {
226 0 : log << log_level_t::fatal
227 0 : << "a mutex attribute structure could not be destroyed, error #"
228 0 : << err
229 0 : << end;
230 0 : pthread_mutex_destroy(&f_impl->f_mutex);
231 0 : throw cppthread_invalid_error("pthread_mutexattr_destroy() failed");
232 : }
233 :
234 : // initialize the condition
235 28 : pthread_condattr_t cattr;
236 28 : err = pthread_condattr_init(&cattr);
237 28 : if(err != 0)
238 : {
239 0 : log << log_level_t::fatal
240 0 : << "a mutex condition attribute structure could not be initialized, error #"
241 0 : << err
242 0 : << end;
243 0 : pthread_mutex_destroy(&f_impl->f_mutex);
244 0 : throw cppthread_invalid_error("pthread_condattr_init() failed");
245 : }
246 28 : err = pthread_cond_init(&f_impl->f_condition, &cattr);
247 28 : if(err != 0)
248 : {
249 0 : log << log_level_t::fatal
250 0 : << "a mutex condition structure could not be initialized, error #"
251 0 : << err
252 0 : << end;
253 0 : pthread_condattr_destroy(&cattr);
254 0 : pthread_mutex_destroy(&f_impl->f_mutex);
255 0 : throw cppthread_invalid_error("pthread_cond_init() failed");
256 : }
257 28 : err = pthread_condattr_destroy(&cattr);
258 28 : if(err != 0)
259 : {
260 0 : log << log_level_t::fatal
261 0 : << "a mutex condition attribute structure could not be destroyed, error #"
262 0 : << err
263 0 : << end;
264 0 : pthread_mutex_destroy(&f_impl->f_mutex);
265 0 : throw cppthread_invalid_error("pthread_condattr_destroy() failed");
266 : }
267 28 : }
268 :
269 :
270 : /** \brief Clean up a mutex object.
271 : *
272 : * This function ensures that the mutex object is cleaned up, which means
273 : * the mutex and conditions get destroyed.
274 : *
275 : * This destructor verifies that the mutex is not currently locked. A
276 : * locked mutex can't be destroyed. If still locked, then an error is
277 : * sent to the logger and the function calls exit(1).
278 : */
279 50 : mutex::~mutex()
280 : {
281 : // Note that the following reference count test only ensure that
282 : // you don't delete a mutex which is still locked; however, if
283 : // you still have multiple threads running, we can't really know
284 : // if another thread is not just about to use this thread...
285 : //
286 25 : if(f_reference_count != 0UL)
287 : {
288 : // we cannot legally throw in a destructor so we instead generate a fatal error
289 : //
290 0 : log << log_level_t::fatal
291 0 : << "a mutex is being destroyed when its reference count is "
292 0 : << f_reference_count
293 0 : << " instead of zero."
294 0 : << end;
295 0 : std::terminate();
296 : }
297 25 : int err(pthread_cond_destroy(&f_impl->f_condition));
298 25 : if(err != 0)
299 : {
300 0 : log << log_level_t::error
301 0 : << "a mutex condition destruction generated error #"
302 0 : << err
303 0 : << end;
304 : }
305 25 : err = pthread_mutex_destroy(&f_impl->f_mutex);
306 25 : if(err != 0)
307 : {
308 0 : log << log_level_t::fatal
309 0 : << "a mutex destruction generated error #"
310 0 : << err
311 0 : << end;
312 : }
313 25 : }
314 :
315 :
316 : /** \brief Lock a mutex
317 : *
318 : * This function locks the mutex. The function waits until the mutex is
319 : * available if it is not currently available. To avoid waiting one may
320 : * want to use the try_lock() function instead.
321 : *
322 : * Although the function cannot fail, the call can lock up a process if
323 : * two or more mutexes are used and another thread is already waiting
324 : * on this process.
325 : *
326 : * \exception cppthread_exception_invalid_error
327 : * If the lock fails, this exception is raised.
328 : */
329 137 : void mutex::lock()
330 : {
331 137 : int const err(pthread_mutex_lock(&f_impl->f_mutex));
332 137 : if(err != 0)
333 : {
334 0 : log << log_level_t::error
335 0 : << "a mutex lock generated error #"
336 0 : << err
337 0 : << " -- "
338 0 : << strerror(err)
339 0 : << end;
340 0 : throw cppthread_invalid_error("pthread_mutex_lock() failed");
341 : }
342 :
343 : // note: we do not need an atomic call since we
344 : // already know we are running alone here...
345 137 : ++f_reference_count;
346 137 : }
347 :
348 :
349 : /** \brief Try locking the mutex.
350 : *
351 : * This function tries locking the mutex. If the mutex cannot be locked
352 : * because another process already locked it, then the function returns
353 : * immediately with false.
354 : *
355 : * \exception cppthread_exception_invalid_error
356 : * If the lock fails, this exception is raised.
357 : *
358 : * \return true if the lock succeeded, false otherwise.
359 : */
360 0 : bool mutex::try_lock()
361 : {
362 0 : int const err(pthread_mutex_trylock(&f_impl->f_mutex));
363 0 : if(err == 0)
364 : {
365 : // note: we do not need an atomic call since we
366 : // already know we are running alone here...
367 0 : ++f_reference_count;
368 0 : return true;
369 : }
370 :
371 : // failed because another thread has the lock?
372 0 : if(err == EBUSY)
373 : {
374 0 : return false;
375 : }
376 :
377 : // another type of failure
378 0 : log << log_level_t::error
379 0 : << "a mutex try lock generated error #"
380 0 : << err
381 0 : << " -- "
382 0 : << strerror(err)
383 0 : << end;
384 0 : throw cppthread_invalid_error("pthread_mutex_trylock() failed");
385 : }
386 :
387 :
388 : /** \brief Unlock a mutex.
389 : *
390 : * This function unlock the specified mutex. The function must be called
391 : * exactly once per call to the lock() function, or successful call to
392 : * the try_lock() function.
393 : *
394 : * The unlock never waits.
395 : *
396 : * \exception cppthread_exception_invalid_error
397 : * If the unlock fails, this exception is raised.
398 : *
399 : * \exception cppthread_exception_not_locked_error
400 : * If the function is called too many times, then the lock count is going
401 : * to be zero and this exception will be raised.
402 : */
403 137 : void mutex::unlock()
404 : {
405 : // We can't unlock if it wasn't locked before!
406 137 : if(f_reference_count <= 0UL)
407 : {
408 0 : log << log_level_t::fatal
409 0 : << "attempting to unlock a mutex when it is still locked "
410 0 : << f_reference_count
411 0 : << " times"
412 0 : << end;
413 0 : throw cppthread_not_locked_error("unlock was called too many times");
414 : }
415 :
416 : // NOTE: we do not need an atomic call since we
417 : // already know we are running alone here...
418 137 : --f_reference_count;
419 :
420 137 : int const err(pthread_mutex_unlock(&f_impl->f_mutex));
421 137 : if(err != 0)
422 : {
423 0 : log << log_level_t::fatal
424 0 : << "a mutex unlock generated error #"
425 0 : << err
426 0 : << " -- "
427 0 : << strerror(err)
428 0 : << end;
429 0 : throw cppthread_invalid_error("pthread_mutex_unlock() failed");
430 : }
431 137 : }
432 :
433 :
434 : /** \brief Wait on a mutex condition.
435 : *
436 : * At times it is useful to wait on a mutex to become available without
437 : * polling the mutex (which uselessly wastes precious processing time.)
438 : * This function can be used to wait on a mutex condition.
439 : *
440 : * This version of the wait() blocks until a signal is received.
441 : *
442 : * \warning
443 : * This function cannot be called if the mutex is not locked or the
444 : * wait will fail in unpredictable ways.
445 : *
446 : * \exception cppthread_exception_not_locked_once_error
447 : * This exception is raised if the reference count is not exactly 1.
448 : * In other words, the mutex must be locked by the caller but only
449 : * one time.
450 : *
451 : * \exception cppthread_exception_mutex_failed_error
452 : * This exception is raised in the event the conditional wait fails.
453 : */
454 0 : void mutex::wait()
455 : {
456 : // For any mutex wait to work, we MUST have the
457 : // mutex locked already and just one time.
458 : //
459 : // note: the 1 time is just for assurance that it will
460 : // work in most cases; it should work even when locked
461 : // multiple times, but it is less likely. For sure, it
462 : // has to be at least once.
463 : //if(f_reference_count != 1UL)
464 : //{
465 : // log << log_level_t::fatal
466 : // << "attempting to wait on a mutex when it is not locked exactly once, current count is "
467 : // << f_reference_count
468 : // << end;
469 : // throw cppthread_exception_not_locked_once_error();
470 : //}
471 0 : int const err(pthread_cond_wait(&f_impl->f_condition, &f_impl->f_mutex));
472 0 : if(err != 0)
473 : {
474 : // an error occurred!
475 0 : log << log_level_t::fatal
476 0 : << "a mutex conditional wait generated error #"
477 0 : << err
478 0 : << " -- "
479 0 : << strerror(err)
480 0 : << end;
481 0 : throw cppthread_mutex_failed_error("pthread_cond_wait() failed");
482 : }
483 0 : }
484 :
485 :
486 : /** \brief Wait on a mutex condition with a time limit.
487 : *
488 : * At times it is useful to wait on a mutex to become available without
489 : * polling the mutex, but only for some time. This function waits for
490 : * the number of specified micro seconds. The function returns early if
491 : * the condition was triggered. Otherwise it waits until the specified
492 : * number of micro seconds elapsed and then returns.
493 : *
494 : * \warning
495 : * This function cannot be called if the mutex is not locked or the
496 : * wait will fail in unpredictable ways.
497 : *
498 : * \exception cppthread_exception_system_error
499 : * This exception is raised if a function returns an unexpected error.
500 : *
501 : * \exception cppthread_exception_mutex_failed_error
502 : * This exception is raised when the mutex wait function fails.
503 : *
504 : * \param[in] usecs The maximum number of micro seconds to wait until you
505 : * receive the signal.
506 : *
507 : * \return true if the condition was raised, false if the wait timed out.
508 : */
509 0 : bool mutex::timed_wait(uint64_t const usecs)
510 : {
511 : // For any mutex wait to work, we MUST have the
512 : // mutex locked already and just one time.
513 : //
514 : // note: the 1 time is just for assurance that it will
515 : // work in most cases; it should work even when locked
516 : // multiple times, but it is less likely. For sure, it
517 : // has to be at least once.
518 : //if(f_reference_count != 1UL)
519 : //{
520 : // log << log_level_t::fatal
521 : // << "attempting to timed wait "
522 : // << usec
523 : // << " usec on a mutex when it is not locked exactly once, current count is "
524 : // << f_reference_count
525 : // << end;
526 : // throw cppthread_exception_not_locked_once_error();
527 : //}
528 :
529 0 : int err(0);
530 :
531 : // get time now
532 0 : struct timespec abstime;
533 0 : if(clock_gettime(CLOCK_REALTIME, &abstime) != 0)
534 : {
535 0 : err = errno;
536 0 : log << log_level_t::fatal
537 0 : << "gettimeofday() failed with errno: "
538 0 : << err
539 0 : << " -- "
540 0 : << strerror(err)
541 0 : << end;
542 0 : throw cppthread_system_error("gettimeofday() failed");
543 : }
544 :
545 : // now + user specified usec
546 0 : abstime.tv_sec += usecs / 1'000'000ULL;
547 0 : std::uint64_t nanos(abstime.tv_nsec + (usecs % 1'000'000ULL) * 1'000ULL);
548 0 : if(nanos > 1'000'000'000ULL)
549 : {
550 0 : ++abstime.tv_sec;
551 0 : nanos -= 1'000'000'000ULL;
552 : }
553 0 : abstime.tv_nsec = static_cast<long>(nanos);
554 :
555 0 : err = pthread_cond_timedwait(&f_impl->f_condition, &f_impl->f_mutex, &abstime);
556 0 : if(err != 0)
557 : {
558 0 : if(err == ETIMEDOUT)
559 : {
560 0 : return false;
561 : }
562 :
563 : // an error occurred!
564 0 : log << log_level_t::fatal
565 0 : << "a mutex conditional timed wait generated error #"
566 0 : << err
567 0 : << " -- "
568 0 : << strerror(err)
569 0 : << " (time out sec = "
570 0 : << abstime.tv_sec
571 0 : << ", nsec = "
572 0 : << abstime.tv_nsec
573 0 : << ")"
574 0 : << end;
575 0 : throw cppthread_mutex_failed_error("pthread_cond_timedwait() failed");
576 : }
577 :
578 0 : return true;
579 : }
580 :
581 :
582 : /** \brief Wait on a mutex until the specified date.
583 : *
584 : * This function waits on the mutex condition to be signaled up until the
585 : * specified date is passed.
586 : *
587 : * \warning
588 : * This function cannot be called if the mutex is not locked or the
589 : * wait will fail in unpredictable ways.
590 : *
591 : * \exception cppthread_exception_mutex_failed_error
592 : * This exception is raised whenever the thread wait function fails.
593 : *
594 : * \param[in] usec The date when the mutex times out in microseconds.
595 : *
596 : * \return true if the condition occurs before the function times out,
597 : * false if the function times out.
598 : */
599 0 : bool mutex::dated_wait(uint64_t usec)
600 : {
601 : // For any mutex wait to work, we MUST have the
602 : // mutex locked already and just one time.
603 : //
604 : // note: the 1 time is just for assurance that it will
605 : // work in most cases; it should work even when locked
606 : // multiple times, but it is less likely. For sure, it
607 : // has to be at least once.
608 : //if(f_reference_count != 1UL)
609 : //{
610 : // log << log_level_t::fatal
611 : // << "attempting to dated wait until "
612 : // << usec
613 : // << " msec on a mutex when it is not locked exactly once, current count is "
614 : // << f_reference_count
615 : // << end;
616 : // throw cppthread_exception_not_locked_once_error();
617 : //}
618 :
619 : // setup the timeout date
620 0 : struct timespec timeout;
621 0 : timeout.tv_sec = static_cast<long>(usec / 1000000ULL);
622 0 : timeout.tv_nsec = static_cast<long>((usec % 1000000ULL) * 1000ULL);
623 :
624 0 : int const err(pthread_cond_timedwait(&f_impl->f_condition, &f_impl->f_mutex, &timeout));
625 0 : if(err != 0)
626 : {
627 0 : if(err == ETIMEDOUT)
628 : {
629 0 : return false;
630 : }
631 :
632 : // an error occurred!
633 0 : log << log_level_t::error
634 0 : << "a mutex conditional dated wait generated error #"
635 0 : << err
636 0 : << " -- "
637 0 : << strerror(err)
638 0 : << end;
639 0 : throw cppthread_mutex_failed_error("pthread_cond_timedwait() failed");
640 : }
641 :
642 0 : return true;
643 : }
644 :
645 :
646 : /** \brief Signal at least one mutex.
647 : *
648 : * Our mutexes include a condition that get signaled by calling this
649 : * function. This function wakes up one or more listening threads.
650 : *
651 : * The function does not lock the mutext before sending the signal. This
652 : * is useful if you already are in a guarded block or you do not mind
653 : * waking up more than one thread as a result of the call.
654 : *
655 : * \note
656 : * If you need to wake up exactly one other thread, then make sure to
657 : * use the safe_signal() function instead.
658 : *
659 : * \exception cppthread_exception_invalid_error
660 : * If one of the pthread system functions return an error, the function
661 : * raises this exception.
662 : *
663 : * \sa safe_signal()
664 : */
665 32 : void mutex::signal()
666 : {
667 32 : int const err(pthread_cond_signal(&f_impl->f_condition));
668 32 : if(err != 0)
669 : {
670 0 : log << log_level_t::fatal
671 0 : << "a mutex condition signal generated error #"
672 0 : << err
673 0 : << end;
674 0 : throw cppthread_invalid_error("pthread_cond_signal() failed");
675 : }
676 32 : }
677 :
678 :
679 : /** \brief Signal a mutex.
680 : *
681 : * Our mutexes include a condition that get signaled by calling this
682 : * function. This function wakes up one listening thread.
683 : *
684 : * The function ensures that the mutex is locked before sending
685 : * the signal so you do not have to lock the mutex yourself.
686 : *
687 : * \exception cppthread_exception_invalid_error
688 : * If one of the pthread system functions return an error, the function
689 : * raises this exception.
690 : *
691 : * \sa signal()
692 : */
693 0 : void mutex::safe_signal()
694 : {
695 0 : guard lock(*this);
696 :
697 0 : int const err(pthread_cond_signal(&f_impl->f_condition));
698 0 : if(err != 0)
699 : {
700 0 : log << log_level_t::fatal
701 0 : << "a mutex condition signal generated error #"
702 0 : << err
703 0 : << end;
704 0 : throw cppthread_invalid_error("pthread_cond_signal() failed");
705 : }
706 0 : }
707 :
708 :
709 : /** \brief Broadcast a mutex signal.
710 : *
711 : * Our mutexes include a condition that get signaled by calling this
712 : * function. This function actually signals all the threads that are
713 : * currently listening to the mutex signal. The order in which the
714 : * threads get awaken is unspecified.
715 : *
716 : * The function ensures that the mutex is locked before broadcasting
717 : * the signal so you do not have to lock the mutex yourself. Note that
718 : * is not required to lock a mutex before broadcasting a signal. The
719 : * effects are similar.
720 : *
721 : * \exception cppthread_exception_invalid_error
722 : * If one of the pthread system functions return an error, the function
723 : * raises this exception.
724 : *
725 : * \sa broadcast()
726 : */
727 0 : void mutex::safe_broadcast()
728 : {
729 0 : guard lock(*this);
730 :
731 0 : int const err(pthread_cond_broadcast(&f_impl->f_condition));
732 0 : if(err != 0)
733 : {
734 0 : log << log_level_t::fatal
735 0 : << "a mutex signal broadcast generated error #"
736 0 : << err
737 0 : << end;
738 0 : throw cppthread_invalid_error("pthread_cond_broadcast() failed");
739 : }
740 0 : }
741 :
742 :
743 : /** \brief Broadcast a mutex signal.
744 : *
745 : * Our mutexes include a condition that get signaled by calling this
746 : * function. This function actually signals all the threads that are
747 : * currently listening to the mutex signal. The order in which the
748 : * threads get awaken is unspecified.
749 : *
750 : * The function ensures that the mutex is locked before broadcasting
751 : * the signal so you do not have to lock the mutex yourself.
752 : *
753 : * \note
754 : * We also offer a safe_broadcast(). If you expect absolutely all the
755 : * other threads to receive the signal, then make sure to use the
756 : * safe_broadcast() function instead. However, if you are already in
757 : * a guarded block, then there is no need for an additional lock and
758 : * this function will work exactly as expected.
759 : *
760 : * \exception cppthread_exception_invalid_error
761 : * If one of the pthread system functions return an error, the function
762 : * raises this exception.
763 : *
764 : * \sa safe_broadcast()
765 : */
766 0 : void mutex::broadcast()
767 : {
768 0 : guard lock(*this);
769 :
770 0 : int const err(pthread_cond_broadcast(&f_impl->f_condition));
771 0 : if(err != 0)
772 : {
773 0 : log << log_level_t::fatal
774 0 : << "a mutex signal broadcast generated error #"
775 0 : << err
776 0 : << end;
777 0 : throw cppthread_invalid_error("pthread_cond_broadcast() failed");
778 : }
779 0 : }
780 :
781 :
782 : /** \brief The system mutex.
783 : *
784 : * This mutex is created and initialized whenever this library is
785 : * loaded. This means it will always be ready for any library
786 : * that depends on the cppthread library.
787 : *
788 : * It should be used for things that may happen at any time and
789 : * require to be done by one thread at a time. For example, a
790 : * class with a get_instance() may want to lock this mutex, do
791 : * it's instance creation and then unlock the mutex.
792 : *
793 : * The mutex locking should be done using the guard class.
794 : *
795 : * \code
796 : * ptr * get_instance()
797 : * {
798 : * cppthread::guard lock(*g_system_mutex);
799 : *
800 : * ...proceed with your instance allocation...
801 : * }
802 : * \endcode
803 : *
804 : * Because of the order in which things get initialized under
805 : * Linux, you can be sure that this mutex will be ready for
806 : * use as soon as the cppthread is loaded. So you can even
807 : * use it in your own C++ initialization (i.e. your global
808 : * objects.)
809 : *
810 : * Obviously, if you also have your own mutex, you need to
811 : * initialize it and therefore you may have problems in
812 : * your initialization process (i.e. your C++ globals may
813 : * not get initialized in the correct order--the mutex may
814 : * get initialized after your other parameters...)
815 : */
816 : mutex * g_system_mutex = nullptr;
817 :
818 :
819 : /** \brief This is an internal function called by the logger constructor.
820 : *
821 : * The logger constructor is called whenever the cppthread library is loaded
822 : * and that happens in your main thread at initialization time. This means
823 : * any of your code can access the g_system_mutex as required.
824 : *
825 : * This function is not defined externally so that other users can't call
826 : * it from the outside (there would be no need anyway). Just in case, if
827 : * called a second time, the function writes an error message and fails
828 : * with a call to std::terminate().
829 : *
830 : * Another way to safely create a new mutex is to use a static variable
831 : * in a function. The initialization of that static variable will always
832 : * be safe so that mutex will be available to all your threads even if
833 : * you already had multiple threads the first time that function was called.
834 : *
835 : * \code
836 : * void myfunc()
837 : * {
838 : * static cppthread::mutex m = cppthread::mutex();
839 : *
840 : * // here "m" is a safe to use mutex
841 : * cppthread::guard lock(m);
842 : *
843 : * ...do atomic work here...
844 : * }
845 : * \endcode
846 : *
847 : * You could even create a function which returns a reference to that
848 : * local mutex (just make sure you don't copy that mutex).
849 : *
850 : * \note
851 : * Although this function gets called from the logger contructor, it is not
852 : * used by the logger at all.
853 : */
854 2 : void create_system_mutex()
855 : {
856 2 : if(g_system_mutex != nullptr)
857 : {
858 0 : std::cerr << "fatal: create_system_mutex() called twice." << std::endl;
859 0 : std::terminate();
860 : }
861 :
862 2 : g_system_mutex = new mutex;
863 2 : }
864 :
865 :
866 :
867 :
868 : /** \typedef mutex::pointer_t
869 : * \brief Shared pointer to a mutex.
870 : *
871 : * You can allocate mutexes as global variables, local variables, variable
872 : * members and once in a while you may want to allocate them. In that
873 : * case, we suggest that you use a shared pointer.
874 : */
875 :
876 :
877 : /** \typedef mutex::vector_t
878 : * \brief A vector of mutexes.
879 : *
880 : * This type defines a vector that can be used to manage mutexes. In
881 : * this case, the mutexes must be allocated.
882 : */
883 :
884 :
885 : /** \typedef mutex::direct_vector_t
886 : * \brief A vector of mutexes.
887 : *
888 : * This type defines a vector of direct mutexes (i.e. not pointers to
889 : * mutexes). This type can be used when you know the number of mutexes
890 : * to allocate. Dynamically adding/removing mutexes with this type
891 : * can be rather complicated.
892 : */
893 :
894 :
895 : /** \var mutex::f_impl
896 : * \brief The pthread mutex implementation.
897 : *
898 : * This variable member holds the actual pthread mutex. The mutex
899 : * implementation manages this field as required.
900 : */
901 :
902 :
903 : /** \var mutex::f_reference_count
904 : * \brief The lock reference count.
905 : *
906 : * The mutex tracks the number of times the mutex gets locked.
907 : * In the end, the lock reference must be zero for the mutex
908 : * to be properly destroyed.
909 : */
910 :
911 :
912 :
913 :
914 6 : } // namespace cppthread
915 : // vim: ts=4 sw=4 et
|