sem_init
value parameter
semaphore initialization
concurrency
programming

sem_init… What is the value parameter for?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The value parameter in sem_init sets the semaphore's initial count. That count determines how many successful sem_wait operations can happen before callers start blocking.

The Meaning of the Initial Value

The function signature is:

c
int sem_init(sem_t *sem, int pshared, unsigned int value);

The third argument, value, is the starting value of the semaphore. Think of it as the number of available permits.

  • 'value = 1 means one thread can pass immediately'
  • 'value = 3 means three threads can pass before blocking'
  • 'value = 0 means nobody passes until another thread calls sem_post'

That is why semaphores are often described as counting semaphores.

Using value = 1 for Mutual Exclusion

A semaphore initialized to 1 behaves a lot like a lock for simple cases:

c
1#include <pthread.h>
2#include <semaphore.h>
3#include <stdio.h>
4
5sem_t sem;
6int shared_counter = 0;
7
8void *worker(void *arg) {
9    for (int i = 0; i < 100000; ++i) {
10        sem_wait(&sem);
11        shared_counter++;
12        sem_post(&sem);
13    }
14    return NULL;
15}
16
17int main(void) {
18    pthread_t t1, t2;
19    sem_init(&sem, 0, 1);
20
21    pthread_create(&t1, NULL, worker, NULL);
22    pthread_create(&t2, NULL, worker, NULL);
23
24    pthread_join(t1, NULL);
25    pthread_join(t2, NULL);
26
27    printf("counter = %d\n", shared_counter);
28    sem_destroy(&sem);
29    return 0;
30}

Because the initial count is 1, only one thread can enter the protected section at a time.

Using a Larger Value to Limit Concurrency

If the resource can safely be used by several threads at once, set a larger initial value.

For example, value = 3 allows up to three threads into the guarded region:

c
1#include <pthread.h>
2#include <semaphore.h>
3#include <stdio.h>
4#include <unistd.h>
5
6sem_t slots;
7
8void *worker(void *arg) {
9    long id = (long)arg;
10    sem_wait(&slots);
11    printf("worker %ld entered\n", id);
12    sleep(1);
13    printf("worker %ld leaving\n", id);
14    sem_post(&slots);
15    return NULL;
16}
17
18int main(void) {
19    pthread_t threads[5];
20    sem_init(&slots, 0, 3);
21
22    for (long i = 0; i < 5; ++i) {
23        pthread_create(&threads[i], NULL, worker, (void *)i);
24    }
25
26    for (int i = 0; i < 5; ++i) {
27        pthread_join(threads[i], NULL);
28    }
29
30    sem_destroy(&slots);
31    return 0;
32}

At most three workers run in the protected section at the same time because the semaphore starts with three permits.

Using value = 0 for Signaling

An initial value of zero is useful when one thread must wait for another thread to announce that work is ready.

c
1#include <pthread.h>
2#include <semaphore.h>
3#include <stdio.h>
4#include <unistd.h>
5
6sem_t ready;
7
8void *producer(void *arg) {
9    sleep(1);
10    printf("producer: data ready\n");
11    sem_post(&ready);
12    return NULL;
13}
14
15int main(void) {
16    pthread_t t;
17    sem_init(&ready, 0, 0);
18
19    pthread_create(&t, NULL, producer, NULL);
20
21    printf("main: waiting\n");
22    sem_wait(&ready);
23    printf("main: received signal\n");
24
25    pthread_join(t, NULL);
26    sem_destroy(&ready);
27    return 0;
28}

Since the initial count is zero, sem_wait blocks until sem_post increments the semaphore.

How to Choose the Right Value

Pick the initial value based on what the semaphore models:

  • a binary gate: use 1
  • a pool of N identical resources: use N
  • a "wait until signaled" event: use 0

The value is not arbitrary. It encodes the starting availability of the resource or event.

pshared Does Not Change the Meaning of value

The pshared argument controls whether the semaphore is shared between threads in one process or between processes. It does not change what value means. The count still represents the number of currently available permits.

Common Pitfalls

The most common mistake is assuming value is a maximum rather than an initial count. It sets the starting number of permits, and later sem_post or sem_wait calls change that number.

Another issue is using value = 1 automatically when the resource actually allows more concurrency. That can serialize work unnecessarily and hurt performance.

People also misuse value = 0 without arranging a matching sem_post. In that case, the waiter blocks forever because no thread ever signals readiness.

Summary

  • The value parameter sets the semaphore's initial count.
  • '1 is common for mutual exclusion, N for a resource pool, and 0 for signaling.'
  • Each successful sem_wait decrements the count, and each sem_post increments it.
  • Choose the value based on how many permits should exist at startup.
  • 'pshared changes sharing scope, not the meaning of the count itself.'

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.