Reading a Semaphore’s Value
Sometimes you need to inspect the current value of a semaphore — for debugging, logging, or to make a conditional decision without modifying the semaphore. POSIX provides sem_getvalue() for this purpose.
Note: the value returned is a snapshot. By the time your code reads it and acts on it, another thread may have changed the semaphore. So never use sem_getvalue() as part of a synchronization decision — use it for informational purposes only.
sem_getvalue() – Function Signature
#include <semaphore.h>
int sem_getvalue(sem_t *sem, int *sval);
/* Returns: 0 on success, -1 on error */
After the call, the integer pointed to by sval holds the current value of the semaphore. If the value is 0 and one or more threads are blocked waiting on the semaphore, the behavior of sval depends on the implementation:
| Implementation | sval when value=0 and threads waiting | Notes |
|---|---|---|
| Linux (glibc) | Returns 0 | Does NOT return negative values |
| Some BSD/older UNIX | May return negative (number of waiters) | Non-standard behavior |
| SUSv3 standard | Unspecified (either 0 or negative) | Do not rely on negative values for portability |
Example: Using sem_getvalue()
#include <stdio.h>
#include <semaphore.h>
void print_sem_value(sem_t *sem, const char *label)
{
int val;
if (sem_getvalue(sem, &val) == -1) {
perror("sem_getvalue");
return;
}
printf("[%s] semaphore value = %d\n", label, val);
}
int main(void)
{
sem_t sem;
sem_init(&sem, 0, 3); /* initial value = 3 */
print_sem_value(&sem, "init");
sem_wait(&sem);
print_sem_value(&sem, "after 1st wait");
sem_wait(&sem);
print_sem_value(&sem, "after 2nd wait");
sem_post(&sem);
print_sem_value(&sem, "after post");
sem_destroy(&sem);
return 0;
}
/* Output:
[init] semaphore value = 3
[after 1st wait] semaphore value = 2
[after 2nd wait] semaphore value = 1
[after post] semaphore value = 2
*/
Why sem_getvalue() Is Not for Synchronization
/* WRONG – do NOT do this */
int val;
sem_getvalue(&sem, &val);
if (val > 0) {
sem_wait(&sem); /* Another thread could have decremented between
getvalue and wait! This is a race condition. */
}
sem_trywait() if you want conditional non-blocking acquisition./* CORRECT – sem_trywait is atomic */
if (sem_trywait(&sem) == 0) {
/* Successfully acquired */
} else {
/* Not available (errno == EAGAIN) */
}
SEM_VALUE_MAX – Maximum Semaphore Value
#include <limits.h> /* or <semaphore.h> */
/* SEM_VALUE_MAX is defined in <limits.h> */
SEM_VALUE_MAX is the maximum value a POSIX semaphore can hold. The POSIX/SUSv3 standard requires it to be at least 32,767. On Linux:
On Linux, SEM_VALUE_MAX equals INT_MAX because the semaphore value is stored as a 32-bit signed integer. You can verify this at runtime:
#include <stdio.h>
#include <limits.h>
#include <semaphore.h>
int main(void)
{
printf("SEM_VALUE_MAX = %d\n", SEM_VALUE_MAX);
/* On Linux: SEM_VALUE_MAX = 2147483647 */
/* Trying to init above SEM_VALUE_MAX fails with EINVAL */
sem_t s;
if (sem_init(&s, 0, SEM_VALUE_MAX) == 0) {
printf("Max value semaphore created OK.\n");
sem_destroy(&s);
}
return 0;
}
What Happens if sem_post() Exceeds SEM_VALUE_MAX?
If calling sem_post() would increment the value beyond SEM_VALUE_MAX, the call fails and returns -1 with errno = EOVERFLOW. The semaphore value is not changed.
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <semaphore.h>
int main(void)
{
sem_t s;
sem_init(&s, 0, SEM_VALUE_MAX);
/* This post would exceed SEM_VALUE_MAX */
if (sem_post(&s) == -1) {
if (errno == EOVERFLOW)
printf("sem_post failed: EOVERFLOW (value at maximum)\n");
else
perror("sem_post");
}
sem_destroy(&s);
return 0;
}
Practical Use: Diagnostics and Debugging
The primary valid use for sem_getvalue() is logging and diagnostics — printing the semaphore state for debugging without modifying it.
#include <stdio.h>
#include <semaphore.h>
/* Debug helper: print all semaphore states */
void dump_semaphore_state(sem_t *sems[], const char *names[], int count)
{
printf("=== Semaphore State Dump ===\n");
for (int i = 0; i < count; i++) {
int val;
sem_getvalue(sems[i], &val);
printf(" %-20s : %d%s\n", names[i], val,
val == 0 ? " [LOCKED/EMPTY]" : "");
}
printf("===========================\n");
}
int main(void)
{
sem_t mutex, empty, full;
sem_init(&mutex, 0, 1);
sem_init(&empty, 0, 5);
sem_init(&full, 0, 0);
sem_t *sems[] = { &mutex, &empty, &full };
const char *names[] = { "mutex", "empty_slots", "full_slots" };
dump_semaphore_state(sems, names, 3);
/* Simulate acquiring mutex and adding item */
sem_wait(&mutex);
sem_wait(&empty);
sem_post(&full);
sem_post(&mutex);
dump_semaphore_state(sems, names, 3);
sem_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
