plibsys 0.0.5
psemaphore.h File Reference

Semaphore routines. More...

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

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 PSemaphorep_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.
 

Detailed Description

Semaphore routines.

Author
Alexander Saprykin

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:

  • Windows doesn't own IPC objects (processes own them), which means that a semaphore will be removed from the system after the last process or thread closes it (or after terminating all the processes and threads holding open semaphore).
  • UNIX systems own IPC objects. Because of that UNIX IPC objects can survive an application crash: an already used semaphore can be opened in a locked state and an application can fail into a deadlock or an inconsistent state. This could happen if you have not closed all the open semaphores explicitly before terminating the application.
  • IRIX allows to open several instances of a semaphore within the single process, but it will close the object after the first close call from any of the threads within the process.
  • AmigaOS has process-wide semaphores without actual tracking of counter, which means that semaphore behaves the same way as recursive mutex.
  • OpenVMS (as of 8.4 release) has declared prototypes for process-wide named semaphores but the actual implementation is broken.
  • OS/2 lacks support for process-wide named semaphores.
  • Syllable lacks support for process-wide named semaphores.
  • BeOS lacks support for process-wide named semaphores.

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 Documentation

◆ PSemaphore

typedef struct PSemaphore_ PSemaphore

Semaphore opaque data structure.

Definition at line 114 of file psemaphore.h.

Enumeration Type Documentation

◆ PSemaphoreAccessMode_

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.

Function Documentation

◆ p_semaphore_acquire()

P_LIB_API pboolean p_semaphore_acquire ( PSemaphore * sem,
PError ** error )

Acquires (P operation) a semaphore.

Parameters
semPSemaphore to acquire.
[out]errorError report object, NULL to ignore.
Returns
TRUE in case of success, FALSE otherwise.
Since
0.0.1

◆ p_semaphore_free()

P_LIB_API void p_semaphore_free ( PSemaphore * sem)

Frees PSemaphore object.

Parameters
semPSemaphore to free.
Since
0.0.1

It doesn't release an acquired semaphore, be careful to not to make a deadlock while removing the acquired semaphore.

◆ p_semaphore_new()

P_LIB_API PSemaphore * p_semaphore_new ( const pchar * name,
pint init_val,
PSemaphoreAccessMode mode,
PError ** error )

Creates a new PSemaphore object.

Parameters
nameSemaphore name.
init_valInitial semaphore value.
modeCreation mode.
[out]errorError report object, NULL to ignore.
Returns
Pointer to a newly created PSemaphore object in case of success, NULL otherwise.
Since
0.0.1

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_semaphore_release()

P_LIB_API pboolean p_semaphore_release ( PSemaphore * sem,
PError ** error )

Releases (V operation) a semaphore.

Parameters
semPSemaphore to release.
[out]errorError report object, NULL to ignore.
Returns
TRUE in case of success, FALSE otherwise.
Since
0.0.1

◆ p_semaphore_take_ownership()

P_LIB_API void p_semaphore_take_ownership ( PSemaphore * sem)

Takes ownership of a semaphore.

Parameters
semSemaphore to take ownership.
Since
0.0.1

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.