se.lth.cs.realtime.semaphore
Interface Semaphore

All Known Implementing Classes:
MultistepSem, MutexSem, CountingSem, BinarySem

public interface Semaphore

Common methods of all types of semaphores, which implements the well-known basic primitive for synchronization and mutual exclusion within the field of concurrent and real-time programming. Basically, a semaphore is an integer-valued variable which can be atomically accessed by only one thread at a time.

Accesses are either of the take type to be used for taking (locking, requesting to continue execution using it, etc.) a resource, or of the give type providing access to the resource (or piece of code) for other threads. These methods, take and give, are defined to have no arguments here, implicitly assuming increments/decrements of one. In addition, classes implementing this interface may define additionally overloaded methods, for other increments or other specific features. Furthermore, the semantics of the take and give with no arguments can differ in different classes.

Note, there is no method defined in this interface for getting the value of the internal counter, and no such method is expected to be provided in any implementing class. That would result in misuse of semaphores, in particular among beginners in concurrent programming. However, a method tryTake has been added to permit a thread to check if a resource could be taken within a certain time, and if so, the semaphore is actually taken. This method has been given a different name (instead of simply overloading take) to point out the different behavior, avoiding programming errors resulting in threads that proceed after a timeout as if the resource had been allocated.


Note about implementations (not for beginners):
The methods take and give are normally not declared synchronized in implementing classes for the following two reasons:
  1. If methods were synchronized and the implementation of blocking is based on wait and notify (see class Object) on the semaphore object itself, there is nothing in Java preventing any thread with a reference to the semaphore to call wait and notify directly in a synchronized block, thereby interfering with the intended behavior of the semaphore methods and probably causing the application to behave erroneously. Instead, blocking/locking is accomplished using a private lock object. It is up to native implementations to accomplish the same thing in more efficient ways.
  2. Disabling interrupts during give and take can be the most appropriate/efficient way of preventing a context switch over the small number of native instructions. Even if a compiler (to native code) is free to accomplish mutual exclusion for small synchronized methods by disabling interrupts, this is from a programming and portability point of view different from explicitly disabling interrupts. A semaphore class for embedded systems, however, is often optimized with respect to the particular platform (OS and HW) and should be considered as a built-in mechanism independently of wait and notify (which may not even be supported natively), and hence the methods (although atomic) should not be viewed as synchronized.

    Another reason for disabling interrupts, mainly for natively compiled applications or special VMs, is to permit give to be called from an interrupt routine (which may not be blocked even temporarily).


Notes for implementations:
Classes implementing this interface should (for security and efficiency reasons mentioned in the above note) be final.

Threads calling the blocking methods (take and tryTake) are to be thrown an error if they are interrupted, as described in the documentation of those methods. As usual, errors (which implements throwable) can be caught, but in normal cases the user program is not expected to catch them.

See Also:
CountingSem, MutexSem, MultistepSem, BinarySem

Method Summary
 void give()
          Increments by 1 the counter represented by this semaphore, and notify at least one, if any, of the waiting threads.
 void take()
          Causes the calling thread to block until the counter that represents this semaphore obtains a positive value.
 boolean tryTake(long timeout)
          Causes the calling thread to block until the counter that represents this semaphore obtains a positive value (just like the ordinary take method) or until the timeout time has passed.
 

Method Detail

give

public void give()
Increments by 1 the counter represented by this semaphore, and notify at least one, if any, of the waiting threads. Basically this means executing the following two lines,
   ++count;
   notify();
atomically (synchronized, with interrupts disabled, or in hardware, as accomplished in a particular type of system).

take

public void take()
Causes the calling thread to block until the counter that represents this semaphore obtains a positive value. On return the counter, named count below, is decremented by 1. Basically this means executing
   while (count<1) wait();
   --count;
atomically (synchronized, with interrupts disabled, or in hardware, as accomplished in each particular type of system).
Throws:
SemInterrupted - (which is an error and not an exception) if the calling thread has been interrupted before or during blocking. The caller is not expected to catch this type of error, except for properly shut-down of the application, since continued execution most likely will violate resource allocation rules and result in concurrency faults.

tryTake

public boolean tryTake(long timeout)
Causes the calling thread to block until the counter that represents this semaphore obtains a positive value (just like the ordinary take method) or until the timeout time has passed.

If, due to other threads calling give, the semaphore is possible to take, but the caller of take is not rescheduled for execution until after the timeout time after its call of take, it is considered as a timeout and hence false is returned (and the internal state of the semaphore is left unchanged).

Returns:
the success of take, that is, true if the semaphore was taken and false if the return was due to a timeout. Hence, be careful to make use of the returned value not to proceed using a resource without really having reserved it.
Throws:
SemInterrupted - (which is an error and not an exception) if the calling thread has been interrupted before or during blocking. The caller is not expected to catch this type of error, except for properly shut-down of the application, since continued execution most likely will violate resource allocation rules and result in concurrency faults.