
PtGate, PosixMonitor and CriticalSection provide a mutual exclusion mechanism. The classes PtCondition and PosixCondition provide a synchronization mechanism. The class PNGeodesic uses these classes to implement a communication channel that enforces the blocking read operations of Kahn process networks and the blocking write operations required for bounded scheduling.
The abstract base class
PtGate defines the interface for mutual exclusion objects in Ptolemy. The class PosixMonitor provides an implementation of PtGate based on the POSIX thread standard. Other implementations are possible. The class PNMonitor is a typedef that determines which implementation is used in the PN domain. Changing the underlying implementation simply requires changing this typedef.PtCondition defines the interface for condition variables in Ptolemy. The class PosixCondition provides an implementation based on the POSIX thread standard. Other implementations are possible. The class PNCondition is a typedef that determines which implementation is used in the PN domain. Changing the underlying implementation simply requires changing this typedef.CriticalSection provides a convenient method for manipulating PtGate objects, preventing some common programming errors. The class PNGeodesic uses all of these classes to implement a communication channel.10.3.1 PtGate
A PtGate can be locked and unlocked, but only one thread can hold the lock. Thus if a thread attempts to lock a PtGate that is already locked by another thread, it is suspended until the lock is released.
virtual void lock() = 0;
This protected method locks the PtGate object for exclusive use by one thread.
virtual void unlock() = 0;
This protected method releases the lock on the PtGate object.
PosixMonitor provides an implementation for the interface defined by PtGate. It has a single protected data member.
pthread_mutex_t thread;
A handle for the POSIX monitor associated with the PosixMonitor object.
lock and unlock methods are shown below.
CriticalSection provides a convenient mechanism for locking and unlocking PtGate objects. Its constructor, shown below, locks the gate. Its destructor, also shown below, unlocks the gate. To protect a section of code, simply create a new scope and declare an instance of CriticalSection. The PtGate is locked as soon as the CriticalSection is constructed. When execution of the code exits scope, the CriticalSection destructor is automatically invoked, unlocking the PtGate and preventing errors caused by forgetting to unlock it. Examples of this usage are shown in Section
10.3.6. Because only one thread can hold the lock on a PtGate, only one section of code guarded in this way can be active at a given time.
CriticalSection(PtGate* g) : mutex(g)
{
if (mutex) mutex->lock();
}
~CriticalSection()
{
if (mutex) mutex->unlock();
}10.3.4 PtCondition
The class PtCondition defines the interface for condition variables in Ptolemy. A PtCondition provides synchronization through the wait and notify methods. A condition variable can be used only when executing code within a critical section (i.e., when a PtGate is locked).
PtGate& mon;
This data member refers to the gate associated with the PtCondition object.
virtual void wait() = 0;
This method suspends execution of the current thread until notification is received. The associated gate is unlocked before execution is suspended. Once notification is received, the lock on the gate is automatically reacquired before execution resumes.
virtual void notify() = 0;
This method sends notification to one waiting thread. If multiple threads are waiting for notification, only one is activated.
virtual void notifyAll() = 0;
This method sends notification to all waiting threads. If multiple threads are waiting for notification, all of them are activated. Once activated, all of the threads attempt to reacquire the lock on the gate, but only one of them succeeds. The others are suspended again until they can acquire the lock on the gate.
PosixCondition provides an implementation for the interface defined by PtCondition. The implementations of the wait, notify and notifyAll methods are shown below.
PNGeodesic, which is derived from the class Geodesic defined in the Ptolemy kernel, implements the communication channels for the PN domain. In conjunction with the PtGate member provided in the base class Geodesic, two condition variables provide the necessary synchronization for blocking read and blocking write operations.
PtCondition* notEmpty;
This data member points to a condition variable used for blocking read operations when the channel is empty.
PtCondition* notFull;
This data member points to a condition variable used for blocking write operations when the channel is full.
int cap;
This data member represents the capacity of the communication channel and determines when it is full.
static int numFull;
This static data member records the number of full geodesics in the system.
slowGet method, shown in below, implements the get operation for communication channels. The entire method executes within a critical section to ensure consistency of the object's data members. If the buffer is empty, then the thread that invoked slowGet is suspended until notification is received on notEmpty. Data is retrieved from the buffer, and if it is not full notification is sent on notFull to any other thread that may have been waiting.
slowPut method, shown below, implements the put operation for communication channels. The entire method executes within a critical section to ensure consistency of the object's data members. If the buffer is full, then the thread that invoked slowPut is suspended until notification is received on notFull. Data is placed in the buffer, and notification is sent on notEmpty to any other thread that may have been waiting.
setCapacity method, shown below, is used to adjust the capacity limit of communication channels. If the capacity is increased so that a channel is no longer full, notification is sent on notFull to any thread that may have been waiting.