Sem

Files CCore/inc/task/Sem.h CCore/src/task/Sem.cpp

Sem is a semaphore, it is a second of the most important synchronization classes.

Sem has an internal semaphore counter. give...() methods increase this counter. Abort() is called in case of overflow. take...() decrements the counter if it is not zero. But if the counter is zero, the method blocks the calling thread until the counter becomes non-zero. Then it decrements the counter.

Consider a basket with apples. Somebody may put an apple to the basket, and somebody may take it, but nobody can take an apple from an empty basket, so he has to wait until the basket becomes non-empty. That is how a semaphore is working, it counts apples in the basket.


class Sem : public Funchor_nocopy
 {
   ....

  public:
   
   // constructors
  
   explicit Sem(ulen count=0);
   
   explicit Sem(TextLabel name,ulen count=0);
   
   ~Sem();
   
   // give
   
   void give();
   
   void give_many(ulen dcount);
   
   // take
   
   bool try_take();
   
   void take();
   
   bool take(MSec timeout);
   
   bool take(TimeScope time_scope); 
    
   // functions
   
   Function<void (void)> function_give() { return FunctionOf(this,&Sem::give); }
 };

The constructor argument count is the initial semaphore counter value. It is zero, by default.

give() increments the counter. If there are waiting threads on the semaphore, the counter is zero and remains zero after operation, but one thread is released.

give_many() increases the semaphore counter by a given value. It may release several threads, waiting the semaphore.

try_take() tries to decrement the semaphore counter. This method never blocks. The return value is true, if the method was successful.

take() decrements the semaphore counter. It may block the calling thread indefinitely, until the operation becomes possible.

take(MSec) and take(TimeScope) are timed variants of the take(). These methods wait up to the specified timeout is expired, then operation failed. The return value is true, if the method was successful.

Here is an example of a typical Sem usage:


template <class T>
class Queue
 {
   QueueContainer<T> queue;
   Mutex mutex;
   Sem sem;

  public:

   Queue() {}

   ~Queue() {}

   void put(T obj)
    {
     {
      Mutex::Lock lock(mutex);

      queue.put(obj);
     }

     // the order is important : put resource first, then give semaphore

     // don't give a semaphore under a mutex lock !

     sem.give();
    }

   T get()
    {
     sem.take();

     // the order is important : take semaphore, then take resource

     {
      Mutex::Lock lock(mutex);

      // it is guaranteed now, the queue is not empty

      return queue.get();
     }
    }
 };

HCore Sem

HCore Sem has the common interface.


class Sem : public Funchor_nocopy
 {
   ....

  public:
   
   // constructors
  
   explicit Sem(ulen count=0);
   
   explicit Sem(TextLabel name,ulen count=0);
   
   ~Sem();
   
   // give
   
   void give();
   
   void give_many(ulen dcount);
   
   // take
   
   bool try_take();
   
   void take();
   
   bool take(MSec timeout);
   
   bool take(TimeScope time_scope); 
    
   // functions
   
   Function<void (void)> function_give() { return FunctionOf(this,&Sem::give); }
 };

XCore Sem

XCore Sem is essentially the same, but has give...() method variants for different execution contexts.


class Sem : public Funchor_nocopy
 {
   ....

  public:
   
   // constructors
  
   explicit Sem(ulen count=0);
   
   explicit Sem(TextLabel name,ulen count=0);
   
   ~Sem();
   
   TextLabel getName() const { return name; }
   
   // give
   
   void give();
   
   void give_int();
   
   void give_any();
   
   void give_many(ulen dcount);
   
   void give_many_int(ulen dcount);
   
   void give_many_any(ulen dcount);
   
   // take
   
   bool try_take();
   
   void take();
   
   bool take(MSec timeout);
   
   bool take(TimeScope time_scope);
   
   // functions
   
   Function<void (void)> function_give() { return FunctionOf(this,&Sem::give); }
   
   Function<void (void)> function_give_int() { return FunctionOf(this,&Sem::give_int); }
   
   Function<void (void)> function_give_any() { return FunctionOf(this,&Sem::give_any); }
 };