Search code examples
csynchronizationthread-safetysemaphorebinary-semaphore

Implementing Counting-Semaphore Using Binary-Semaphore


I have implemented sort of user level threads system.I need some help with implementation of a counting semaphore, using binary semaphore implementation(up and down functions as described below). Here is the interface of my implementation of a binary semaphore:

typedef enum BinSemStatus{
   locked,
   unlocked
} BinSemStatus;


struct semaphore {
BinSemStatus status;
int bid;
};

int bsem_alloc();//allocate a new binary semaphore,return its descriptor
void bsem_free(int id);
void bsem_down(int id);
void bsem_up(int id);

And here is the interface of the counting semaphore interface:

struct counting_semaphore* counting_alloc(uint value);
counting_free(struct counting_semaphore* sem);

// If the value representing the count of
// the semaphore variable is not negative, decrement it by 1. If the 
// semaphore variable is now
// negative, the thread executing acquire is blocked until the value is 
// greater or equal to 1.
// Otherwise, the thread continues execution.
void up(struct counting_semaphore* sem);
// Increments the value of semaphore
// variable by 1.
void down(struct counting_semaphore* sem);

What I have tried to do is at void up(struct counting_semaphore* sem) to lock value.But as you can see below that is not enough.I have added a comment at the problematic case.

struct counting_semaphore {
int binary_descriptor;
int value;
}; 

void down(struct counting_semaphore *sem){
  bsem_down(sem->binary_descriptor);
  if (sem->value > 0){
    sem->value--;
  }
  else{
     //not sure what to do here, maybe use anather semaphore in some way?
  } 
  bsem_up(sem->binary_descriptor);
 }
void up(struct counting_semaphore *sem){
  bsem_down(sem->binary_descriptor);
  sem->value++;
  bsem_up(sem->binary_descriptor);
}

Solution

  • The critical section is guarded by sem->binary_descriptor1 and each of the operations down(S) and up(S) uses it to correctly update the value of sem.value

    After updating both operations release the sem->binary_descriptor2 semaphore only if the value is positive.

    S.value is never negative because any process performing down(S) is blocked at sem->binary_descriptor2.

      struct counting_semaphore* counting_semaphore_alloc(int value) {
    
        struct counting_semaphore* sem = malloc(sizeof(struct counting_semaphore));
        sem->value = value;
        sem->binary_descriptor1= bsem_alloc();//locks the value
        sem->binary_descriptor2= bsem_alloc();//locks the sing of the value
        if (value <= 0) {
            bsem_down(sem->binary_descriptor2);
        }
        return sem;
        }
    
    void down(struct counting_semaphore *sem){
        bsem_down(sem->binary_descriptor2);
        bsem_down(sem->binary_descriptor1);
        sem->value--;
        if (sem->value>0){
            bsem_up(sem->binary_descriptor2);
        }
        bsem_up(sem->binary_descriptor1);
    }
    
    
    void up(struct counting_semaphore* sem) {
        bsem_down(sem->binary_descriptor1);
        sem->value++;
        if (sem->value == 1) {
            bsem_up(sem->binary_descriptor2);
        }
        bsem_up(sem->binary_descriptor1);
    }