#include <wefts_critical.h>
Inheritance diagram for Wefts::CriticalSection:
This concept is mainly provided for higher level languages in which some sort of automatic processing has to be taken outside the control of the final programmers. In example, on Virtual Machine based high level languages, a form of garbage collecting is often provided. Some fast and efficient implementations of the garbage collector need to be handled by a thread which can count of the memory to stay untouched for the whole duration of collection loops.
Moreover, suspension of other threads may be targeted only to some kind of threads; in the example, the garbage collector would be willing to stop all related VM threads, but the applications may know that other threads are not affecting collection operations, and so there isn't the need to stop them.
At low level, if the application wills to maintain tread safety, it is necessary the active cooperation of target suspendable threads. Threads that may be stopped if a certain critical section is entered by another thread must grant that they can be suspended at a certain point, so that their suspension happens safely, after releasing all the resources that the critical section user may need.
For this reason, this class is called "critical section implementation support". There is no (safe) way to provide a raw suspension of unwilling threads; instead, this class provide an easy interface to grant thread safe suspension of threads willing to cooperate with portion of code needing critical section semantic. This also helps to provide critical sections for higher level languages, or scripting languages, that may be implemented by using wefts as multithreading support.
This is the support provided: a thread willing to cooperate on a determinate critical section will call the CriticalSection::signIn() method at its begin, or when its cooperation becomes necessary. If the critical section is not currently being held, the call will return immediately, and the calling thread will be now accounted for critical section usage, else the call will return when the critical section is released.
Then, whenever the cooperation of the thread is not needed anymore, it will call the CriticalSection::signOut() method; this call is not blocking.
A thread that may pause for a long time should sign out before doing the pause, and sign in again after the pause has elapsed; also, a thread that knows that it's going to take some long operations in which the data guarded by the critical section is not used should sign out, so to signal other threads willing to enter the critical section that they are temporarily out of business.
If a thread is canceled while it's signed in for a critical section, the thread is not automatically signed out; it's necessary to call the CriticalSection::signOut() method in it's cleanup routine to avoid deadlocks due to waits for critical sections waiting threads never become clear to go.
A thread willing to enter a critical section must call the method CriticalSection::enter(). This will block the calling thread until it is the only thread interested in the critical section. To prevent other threads to sign in the section while the thread is waiting to enter it, a boolean true parameter may be passed to the enter method; normally, the other threads will be able to sign out and in again up to the moment that the calling thread is waked up and able to enter the section, but using this option the critical section requestor will prevent other threads to sign in even if it has not yet entered it. When the thread is done, it must call CriticalSection::leave() to allow other threads to sign in or enter again.
If more than a thread is willing to enter a critical section, and if they are using the resources the critical section holders may use inside and outside the critical section, then they should sign in normally and sign out right before try to enter the section. Otherwise, if the thread wishing to achieve a critical section uses the resources only inside the section, they need not to sign in.
CriticalSection class provides also timed waits on enter method and a try semantic that checks for section achieve being immediately available.
Finally, if a cooperating thread, one of which signed in for the section, is engaged in some long operation in which periodically holds the resources, it should call from time to time the CriticalSection::checkPoint() method. This won't sign out the resource, but it will eventually suspend resource control if there is a thread waiting for critical section entrance.
Enter (both timed version and infinite wait versions), signIn and checkPoint methods are cancellation points. The thread must be clean (or push an adequate cleanup handler) before calling them; checkPoint() automatically signs out the resources if a cancellation is issued, but enter() does not (as the calling thread is not required to sign in to call it). Anyhow, it's necessary to sign out a signed in thread before calling enter() or that thread will infinitely wait for itself to sign out.
Public Member Functions | |
CriticalSection () | |
Initializes the critical section. | |
bool | enter (bool fence=true, bool timed=false, double time=0) |
Enters the critical section. | |
bool | enter (double time, bool fence=true) |
Enter a critical section for a maximum of a given amount of seconds. | |
bool | tryEnter () |
Try to enter a critical section and returns immediately. | |
void | leave () |
Leaves the critical sections, allowing other threads to proceed. | |
void | signIn () |
Claims the critical section to be not enterable. | |
void | signOut () |
Signals that the current thread is not interested in the critical section anymore. | |
void | checkPoint () |
Allows critical section entering if possible. | |
virtual void | handleCleanup (int code, void *caller=0) |
Private Attributes | |
int | m_signedIn |
Count of signed in threads. | |
int | m_signRequests |
Count of threads wishing to sign in. | |
int | m_enterRequests |
Count of threads wishing enter the critical section. | |
int | m_fenceCount |
Fence count for enter requests. | |
bool | m_achieved |
True if currently achieved by a thread. | |
Mutex | m_mutex |
Mutex to protect internal data. | |
Condition | m_signinCond |
Condition for threads wishing to sign in. | |
Condition | m_enterCond |
Condition for threads willing to enter the section. |
|
Initializes the critical section. This is not an inlined method. |
|
Allows critical section entering if possible. If the current thread does not wants to sign out, but it is doing some interruptible but long work on the data set guarded by the critical section, it may wish to call this method at some point, or periodically. This method will block and allow the thread(s) that asked for critical section entering to proceed, if they risen a fence or if this is the only currently signed in thread.
|
|
Enter a critical section for a maximum of a given amount of seconds. Works as enter( bool ), except for the fact that it returns false if the thread is not able to enter the critical section in the given time, or true if the section is achieved.
|
|
Enters the critical section. The calling thread will be suspended until the count of signed in threads will reach 0, and the critical section is not achieved by other threads. If the fence parameter is true, a fence is risen; this fence blocks other threads willing to sign in, and blocks also threads entering check points. Anyhow, it won't prevent other threads from entering the critical section. In example, if two threads try to enter a critical section, and one of them rises the fence, the other threads willing to sign in or entering a checkpoint will be stopped, but there is no guarantee that the fencing thread will enter the section before the other. Anyhow, it's guaranteed that the fencing thread will be eventually called before that a new thread has the chance to successfully sign in or exit a checkpoint. If the fence parameter is false, then this thread will have to wait for all the threads to be signed out, or to engage at the same time a checkpoint before to proceed. This may happened randomly, or it may happen consistently if the program is designed to have many waits inside the singed in threads. Be the fence parameter true or false, once that the thread has entered the critical section, no thread is allowed to go past a checkpoint or to sign in, up to when the owning thread calls the leave method. If the thread calling this method is also signed in, it MUST sign out before to call enter, or it will hang forever. The timed parameter serves to know if the time parameter must be considered. If timed is true, the function will return true if the function is able to enter the section in the given time interval, or false if it fails. Typically, you'll want to use candy grammar version enter( double, bool ).
|
|
Implements Wefts::CleanupHandler. |
|
Leaves the critical sections, allowing other threads to proceed. If there are other threads waiting for the critical section to become enterable, and fence is risen they are awaken. Else, threads waiting to sign in are awaken. |
|
Claims the critical section to be not enterable. Calling this thread states that it must work on the application data so that the critical section may not be entered safely. Notice that if the data set guarded this way was simple and consistent, a mutex or a read write mutex would be fare enough to handle this situation. But when the data set becomes very complex, or it's not even defined because it may vary from time to time, usage of a critical section semantics becomes important. Any number of threads may sign in for a critical section, but only one is allowed to enter it; and it can enter it only if no other thread has signed in. Also, by entering a critical section, sign in is temporarily forbidden. Timed sign in and sign in tries semantics are not provided because critical section holding is meant to be sporadic and temporary; it has no sense to ask if the current thread may or may not be blocked as a sign in request, because the sign in request significance is exactly to block the thread if the critical section is currently entered.
|
|
Signals that the current thread is not interested in the critical section anymore. With this call, the current thread tells eventual other threads wishing to enter the section that they may do it now, as even if the thread continues to work, it will not harm or use the critical section guarded data. |
|
Try to enter a critical section and returns immediately. If the critical section is immediately available, the thread enters it and the function returns true; else, it returns false. Its a candy grammar for enter( fence, true, time );
|
|
True if currently achieved by a thread. This prevents multiple threads to achieve the section when the signed in count reaches zero. |
|
Condition for threads willing to enter the section. This condition serves for the predicate ( !m_achieved && m_signedIn == 0 ). Will be signaled only if m_enterRequests != 0. |
|
Count of threads wishing enter the critical section.
|
|
Fence count for enter requests.
|
|
Mutex to protect internal data.
|
|
Count of signed in threads. When it's 0, the critical section may be entered. |
|
Condition for threads wishing to sign in. This condition serves for the predicate ( !m_achieved && m_fenceCount == 0 ). Will be signaled only if m_signRequests != 0. |
|
Count of threads wishing to sign in.
|