[NAME] ALL.module.standard.sync [TITLE] Synchronization [DESCRIPTION] Mutex, conditional variable and semaphore are the convetional way for thread synchronization. These constructs synchronize tasklet by block the native threads, so they are not the recommended way for synchronization and communication channels are the preferrable way. 0.1 Mutex Mutex can be used to synchronize the accessing of shared data structures. It has two state: locked and unlocked. A mutex can be locked by only one thread. A thread is suspended when it attempt to lock a mutex which has been locked by another thread. 1 mutex = mutex(); Then it can be locked or unlocked by, 1 mutex.lock(); 2 mutex.unlock(); 3 mutex.trylock(); By calling lock(), the calling thread will be block if the mutex is already locked by another thread. If the mutex is locked by the same thread, a second calling of lock() may cause a deadlock. trylock() is the same as lock() except that it will return immediately instead of blocking the calling thread if the mutex is already locked. 0.2 Condition Variable Condition variable is a synchronization device which allow a thread to be suspended if a condition is not satisified and resume execution when it is signaled. The basic operations on a condition is: wait on the condition, or signal the condition. 1 condvar = condition(); Condition variable should always be used together with a mutex. To wait on a condition, 1 mtx.lock() 2 condvar.wait( mtx ); 3 mtx.unlock(); To wait on a condition for a maximum time, 1 mtx.lock() 2 condvar.timedwait( mtx, seconds ); 3 mtx.unlock(); seconds can be a decimal, for example, condvar.timedwait( mtx, 0.005 ) will wait for five miliseconds. 0.3 Semaphore Semaphore can be used to set a limit on resources. It maintains a count for the resource, and allows a thread to proceed, when it attempts to decrease a non-zero count. If the count already reaches 0 before the decrement, the thread will be suspended until the count becomes non-zero. When the thread finished using the resource, it should increase the count of semaphore. A semaphore must be created with an initial count, 1 sema = semaphore( count ); To access a resource guarded by a semaphore, use, 1 sema.wait() If the resource is acquired, the count of sema will be decreased. To release the resource, use 1 sema.post() which will increase the count. 0.4 State State is an abstraction layer for multiple condition variables coupled with the principles of atomic operations. Semantically, it represent a state of certain process or object which can be set, altered or waited upon by arbitrary number of concurrent tasks. A state contains single value which can be assigned or modified using test-and-set and fetch-and-add principles. One or more threads can wait until a state reaches certain value, in this case the synchronization is similar to using conditional variables with broadcasting. A state can represent an int, float, double, complex or enum value: 1 st = state<int>(0); 2 3 type status = enum<on; off; running; idle; finished; canceled> 4 st2 = state<status>($on + $idle); To perform basic read and write, value() and set() are provided, the latter returns the old value of a state: 1 if (st.value() == 0) 2 old = st2.set($off); alter(old, new) can be used to assign new value to a state if it currently contains old value. The routine returns non-zero if the operation has succeeded: 1 success = st.alter(0, 1); 2 3 if (success){ 4 ... #will be executed by the only succeeded thread 5 } add() and sub() are meant to add/substract for numeric values and append/remove symbols for a combined enum. The old value of state is returned: 1 old = st.sub(1); 2 st2.add($finished); To block the current thread until a state is assigned the desired value, wait() is to be used. A timeout may specified, in this case the routine will return zero if time-outed. To determine what values are currently awaited by other threads, waitlist() is provided: 1 if (2 not in st.waitlist()) 2 success = st.wait(1, 5.0);