summaryrefslogtreecommitdiff
path: root/3rdparty/plibsys/src/pcondvariable.h
blob: d69c8b99efe56501a61d29a7e47133809c82ee6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * The MIT License
 *
 * Copyright (C) 2010-2016 Alexander Saprykin <saprykin.spb@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file pcondvariable.h
 * @brief Condition variable
 * @author Alexander Saprykin
 *
 * A condition variable is an inter-thread synchronization primitive, often
 * used in the classical 'producers-consumers' concurrent data access models.
 *
 * The main idea is to notify waiting thread(s) for some events before they
 * can enter a critical section. Hence the name of the primitive: a thread
 * enters the critical section upon an accomplished condition. Compare it with a
 * mutex where the thread enters the critical section as soon as no one holds a
 * lock.
 *
 * Several threads can be notified at once, but only one of them can enter the
 * critical section. The order of the threads in that case is implementation
 * dependent.
 *
 * As the thread enters the critical section upon a condition it still requires
 * a mutex to guard its code against concurrent access from other threads. The
 * mutex provided in pair with a condition variable will be automatically locked
 * on the condition, the thread should unlock it explicitly after leaving the
 * critical section. That mutex is unlocked while waiting for the condition and
 * should be locked prior calling the condition waiting routine.
 *
 * The waiting thread behavior: create a new condition variable with
 * p_cond_variable_new(), create and lock a mutex before a critical section and
 * wait for a signal from another thread on this condition variable
 * using p_cond_variable_wait().
 *
 * The signaling thread behavior: upon reaching event time emit a signal with
 * p_cond_variable_signal() to wake up a single waiting thread or
 * p_cond_variable_broadcast() to wake up all the waiting threads.
 *
 * After emitting the signal only the one thread will get the locked mutex back
 * to continue executing the critical section.
 *
 * It is implementation dependent whether a thread will receive a missed signal
 * (when a notification from the one thread was emitted prior another thread has
 * been called for waiting), so do not rely on this behavior.
 */

#if !defined (PLIBSYS_H_INSIDE) && !defined (PLIBSYS_COMPILATION)
#  error "Header files shouldn't be included directly, consider using <plibsys.h> instead."
#endif

#ifndef PLIBSYS_HEADER_PCONDVARIABLE_H
#define PLIBSYS_HEADER_PCONDVARIABLE_H

#include <pmacros.h>
#include <ptypes.h>
#include <pmutex.h>

P_BEGIN_DECLS

/** Condition variable opaque data structure. */
typedef struct PCondVariable_ PCondVariable;

/**
 * @brief Creates a new #PCondVariable.
 * @return Pointer to a newly created #PCondVariable structure, or NULL if
 * failed.
 * @since 0.0.1
 */
P_LIB_API PCondVariable *	p_cond_variable_new		(void);

/**
 * @brief Frees #PCondVariable structure.
 * @param cond Condtion variable to free.
 * @since 0.0.1
 */
P_LIB_API void			p_cond_variable_free		(PCondVariable	*cond);

/**
 * @brief Waits for a signal on a given condition variable.
 * @param cond Condition variable to wait on.
 * @param mutex Locked mutex which will remain locked after waiting.
 * @return TRUE on success, FALSE otherwise.
 * @since 0.0.1
 *
 * The calling thread will sleep until the signal on @a cond arrived.
 */
P_LIB_API pboolean		p_cond_variable_wait		(PCondVariable	*cond,
								 PMutex		*mutex);

/**
 * @brief Emitts a signal on a given condition variable for one waiting thread.
 * @param cond Condition variable to emit the signal on.
 * @return TRUE on success, FALSE otherwise.
 * @since 0.0.1
 *
 * After emitting the signal only the one thread waiting for it will be waken
 * up. Do not rely on a queue concept for waiting threads. Though the
 * implementation is intended to be much close to a queue, it's not fairly
 * enough. Due that any thread can be waken up, even if it has just called
 * p_cond_variable_wait() while there are other waiting threads.
 */
P_LIB_API pboolean		p_cond_variable_signal		(PCondVariable	*cond);

/**
 * @brief Emitts a signal on a given condition variable for all the waiting
 * threads.
 * @param cond Condition variable to emit the signal on.
 * @return TRUE on success, FALSE otherwise.
 * @since 0.0.1
 *
 * After emitting the signal all the threads waiting for it will be waken up.
 */
P_LIB_API pboolean		p_cond_variable_broadcast	(PCondVariable	*cond);

P_END_DECLS

#endif /* PLIBSYS_HEADER_PCONDVARIABLE_H */