1

So my problem is simple, I need to know how many threads are waiting for the semaphore(are queued). Initially I thought sem_getvalue would return a negative number showing the number of threads blocked by the semaphore but it only goes down to 0 and stays there. I also tried to declare a global variable like int waiting and incrementing it before calling sem_wait with waiting++ and decrementing it after the call but it seems like this solution is not working(by which I am baffled because I thought incrementing and decrementing won't cause race condition). I have looked at the semaphore.h but none of the functions seem to do what I want. Writing here, I came up with an imperfect solution of declaring a second semaphore and initializing it with 0 then calling sem_post on it before the actual sem_wait and a wait after the actual wait. Haven't tested whether it works but even if it does it seems a little hacky a not very nice!

Ali Rahimi
  • 394
  • 4
  • 12
  • https://pubs.opengroup.org/onlinepubs/7908799/xsh/sem_getvalue.html according to the doc it does exactly what you want. Maybe post your code? – littleadv Jan 24 '22 at 08:32
  • Unfortunately: POSIX.1 permits two possibilities for the value returned in sval: either 0 is returned; or a negative number whose absolute value is the count of the number of processes and threads currently blocked in sem_wait(3). Linux adopts the former behavior. – Ali Rahimi Jan 24 '22 at 08:38
  • Increment/decrement is a read-calculate-write-operation, so it is not thread-safe. If you protect the `waiting` counter with a dedicated mutex, then that should work. – nielsen Jan 24 '22 at 08:42
  • C doesn't guarantee there won't be any race conditions even with simple increment/decrement in one thread and reads in another - unless the variables involved are `_Atomic`. – Lundin Jan 24 '22 at 08:43
  • There is something wrong with your design if you attempt this for any reason other than, maybe, debugging. I have written a lot of multithreaded apps and have never found a need to monitor a semaphore count. – Martin James Jan 24 '22 at 13:03

1 Answers1

1

Without getting into why you have a lot of threads waiting on a semaphore, one way to solve this is what you already have tried, having a counter. This counter has to be *atomic*, or do something like:

pthread_mutex_t wait_m = PTHREAD_MUTEX_INITIALIZER;
int wait_counter = 0;

void inc_wait_counter() 
{
    pthread_mutex_lock(&wait_m);
    wait_counter ++;
    pthread_mutex_unlock(&wait_m);

}

void dec_wait_counter() 
{
    pthread_mutex_lock(&wait_m);
    wait_counter --;
    pthread_mutex_unlock(&wait_m);

}

int get_wait_counter()
{
    /* No need to lock here for only reading wait_counter */
    return wait_counter;
}

Then just something like:

inc_wait_counter();
sem_wait(...);
dec_wait_counter();

NOTE: Using atomic integers instead, I suggest to check: How to do an atomic increment and fetch in C?

Morgan V
  • 71
  • 3
  • In many cases, `get_wait_counter()` will be ok without a lock, but it cannot be guaranteed that writing an integer is an atomic operation (e.g. on an 8-bit processor which nowadays is still found in some embedded systems). So unless integer write (also considering the alignment of the `wait_counter` variable) is known to be atomic on the given system, a lock should be used also for read. – nielsen Jan 24 '22 at 08:56