plibsys 0.0.5
|
Semaphore routines. More...
Go to the source code of this file.
Typedefs | |
typedef enum PSemaphoreAccessMode_ | PSemaphoreAccessMode |
Enum with semaphore creation modes. | |
typedef struct PSemaphore_ | PSemaphore |
Semaphore opaque data structure. | |
Enumerations | |
enum | PSemaphoreAccessMode_ { P_SEM_ACCESS_OPEN = 0 , P_SEM_ACCESS_CREATE = 1 } |
Enum with semaphore creation modes. More... | |
Functions | |
P_LIB_API PSemaphore * | p_semaphore_new (const pchar *name, pint init_val, PSemaphoreAccessMode mode, PError **error) |
Creates a new PSemaphore object. | |
P_LIB_API void | p_semaphore_take_ownership (PSemaphore *sem) |
Takes ownership of a semaphore. | |
P_LIB_API pboolean | p_semaphore_acquire (PSemaphore *sem, PError **error) |
Acquires (P operation) a semaphore. | |
P_LIB_API pboolean | p_semaphore_release (PSemaphore *sem, PError **error) |
Releases (V operation) a semaphore. | |
P_LIB_API void | p_semaphore_free (PSemaphore *sem) |
Frees PSemaphore object. | |
Semaphore routines.
A semaphore is a synchronization primitive which controls access to shared data from the concurrently running threads. Unlike a mutex (which is a particular case of a binary semaphore) it allows concurrent access not to only the one thread.
The semaphore has a counter which means the number of available resources (units). Before entering a critical section a thread must perform the so called P (acquire) operation: if the counter is positive it decrements the counter by 1 and continues execution; otherwise the thread is suspended until the counter becomes positive. Before leaving the critical section the thread must perform the so called V (release) operation: increments the counter by 1 and wakes up a waiting thread from the queue (if any).
You can think about the semaphore as a resource controller: the P operation takes one unit, while the V operation gives one unit back. The thread could not continue execution without taking a resource unit. By setting the initial semaphore counter value you can control how much concurrent threads can work with a shared resource.
This semaphore implementation is process-wide so you can synchronize not only the threads. But it makes this IPC primitive (actually like any other IPC primitive, as well) relatively heavy. Consider using a mutex or a spinlock instead if you do not need to cross a process boundary.
A process-wide semaphore is identified by its name across the system, thus it is also called a named semaphore. Use p_semaphore_new() to open the named semaphore and p_semaphore_free() to close it.
Please note the following platform specific differences:
Use the third argument as P_SEM_ACCESS_CREATE in p_semaphore_new() to reset a semaphore value while opening it. This argument is ignored on Windows. You can also take ownership of the semaphore with p_semaphore_take_ownership() to explicitly remove it from the system after closing.
Definition in file psemaphore.h.
typedef struct PSemaphore_ PSemaphore |
Semaphore opaque data structure.
Definition at line 114 of file psemaphore.h.
Enum with semaphore creation modes.
Enumerator | |
---|---|
P_SEM_ACCESS_OPEN | Opens an existing semaphore or creates one with a given value.
|
P_SEM_ACCESS_CREATE | Creates semaphore, resets to a given value if exists.
|
Definition at line 108 of file psemaphore.h.
P_LIB_API pboolean p_semaphore_acquire | ( | PSemaphore * | sem, |
PError ** | error ) |
Acquires (P operation) a semaphore.
sem | PSemaphore to acquire. | |
[out] | error | Error report object, NULL to ignore. |
P_LIB_API void p_semaphore_free | ( | PSemaphore * | sem | ) |
Frees PSemaphore object.
sem | PSemaphore to free. |
It doesn't release an acquired semaphore, be careful to not to make a deadlock while removing the acquired semaphore.
P_LIB_API PSemaphore * p_semaphore_new | ( | const pchar * | name, |
pint | init_val, | ||
PSemaphoreAccessMode | mode, | ||
PError ** | error ) |
Creates a new PSemaphore object.
name | Semaphore name. | |
init_val | Initial semaphore value. | |
mode | Creation mode. | |
[out] | error | Error report object, NULL to ignore. |
The init_val is used only in one of following cases: a semaphore with the such name doesn't exist, or the semaphore with the such name exists but mode specified as P_SEM_ACCESS_CREATE (non-Windows platforms only). In other cases init_val is ignored. The name is system-wide, so any other process can open that semaphore passing the same name.
P_LIB_API pboolean p_semaphore_release | ( | PSemaphore * | sem, |
PError ** | error ) |
Releases (V operation) a semaphore.
sem | PSemaphore to release. | |
[out] | error | Error report object, NULL to ignore. |
P_LIB_API void p_semaphore_take_ownership | ( | PSemaphore * | sem | ) |
Takes ownership of a semaphore.
sem | Semaphore to take ownership. |
If you take ownership of a semaphore object, p_semaphore_free() will try to completely unlink it and remove from the system. This is useful on UNIX systems where the semaphore can survive an application crash. On the Windows platform this call has no effect.
The common usage of this call is upon application startup to ensure that the semaphore from the previous crash will be unlinked from the system. To do that, call p_semaphore_new(), take ownership of the semaphore object and remove it with the p_semaphore_free() call. After that, create it again.
You can also do the same thing upon semaphore creation passing P_SEM_ACCESS_CREATE to p_semaphore_new(). The only difference is that you should already know whether this semaphore object is from the previous crash or not.