Copyright (c) Hyperion Entertainment and contributors.
Difference between revisions of "Exec Mutexes"
Steven Solie (talk | contribs) |
Steven Solie (talk | contribs) |
||
Line 13: | Line 13: | ||
# All tasks using shared data that is protected by a mutex must ''always ask for the mutex first before accessing the data''. If some task accesses the data directly without first going through the mutex, the data may be corrupted. No task will have safe access to the data. |
# All tasks using shared data that is protected by a mutex must ''always ask for the mutex first before accessing the data''. If some task accesses the data directly without first going through the mutex, the data may be corrupted. No task will have safe access to the data. |
||
# A deadlock will occur if a task that owns a mutex on some data inadvertently calls another task which tries to get the mutex on that same data. Deadlocks and other such issues are beyond the scope of this manual. For more details on deadlocks and other problems of shared data in a multitasking system and the methods used to prevent them, refer to [http://en.wikipedia.org/wiki/Deadlock Wikipedia]. |
# A deadlock will occur if a task that owns a mutex on some data inadvertently calls another task which tries to get the mutex on that same data. Deadlocks and other such issues are beyond the scope of this manual. For more details on deadlocks and other problems of shared data in a multitasking system and the methods used to prevent them, refer to [http://en.wikipedia.org/wiki/Deadlock Wikipedia]. |
||
+ | |||
+ | == Creating a Mutex == |
||
+ | |||
+ | There is only one way to create a Mutex and that is via the AllocSysObject() function with an object type of ASOT_MUTEX. The mutex is an opaque pointer taht is not open to the public. |
||
+ | |||
+ | Here is an example showing how to create a mutex: |
||
+ | |||
+ | <syntaxhighlight> |
||
+ | APTR mutex = IExec->AllocSysObjectTags(ASOT_MUTEX, |
||
+ | ASOMUTEX_Recursive, FALSE, // The default is to create a recursive mutex. |
||
+ | TAG_END); |
||
+ | </syntaxhighlight> |
||
+ | |||
+ | == Obtaining a Mutex == |
||
+ | |||
+ | The MutexObtain() function can be used to get a lock on a mutex. If another task currently has a lock on the mutex, your task will be put to sleep until all locks on the the mutex are released. If the same task tries to lock the mutex a second time the behaviour depends on whether the mutex was created with the recursive property or not. |
||
+ | |||
+ | {| class="wikitable" |
||
+ | | ''Mutex Nesting.'' Mutexes have optional nesting. If the mutex is recursive, a lock by the same task on the same mutex will always succeed. If the mutex is not recursive, a lock by the same task on the same mutex will always fail. Which mode is most appropriate depends on the design of the application. |
||
+ | |} |
||
+ | |||
+ | To obtain a mutex use: |
||
+ | |||
+ | <syntaxhighlight> |
||
+ | APTR mutex; |
||
+ | IExec->MutexObtain(mutex); |
||
+ | </syntaxhighlight> |
||
+ | |||
+ | == Checking a Mutex == |
||
+ | |||
+ | When you attempt to obtain a mutex with MutexObtain(), your task will be put to sleep if the mutex is not currently available. If you do not want to wait, you can call MutexAttempt(). If the mutex is available for locking, MutexAttempt() obtains it for you and returns TRUE. If it is not available, the function returns FALSE immediately instead of waiting for the mutex to be released. |
||
+ | |||
+ | The MutexAttemptWithSignal() function is similar to MutexAttempt() but will block if the mutex cannot be obtained. What makes MutexAttemptWithSignal() special is that it will unblock if the mutex is released or if a predefined signal is received. Being able to block on a mutex or a signal removes the need for any Forbid()/Permit() locking in such situations. |
||
+ | |||
+ | To attempt to obtain a mutex, use the following: |
||
+ | |||
+ | <syntaxhighlight> |
||
+ | APTR mutex; |
||
+ | IExec->MutexAttempt(mutex); |
||
+ | </syntaxhighlight> |
||
+ | |||
+ | To make an attempt to obtain a mutex or a signal, the following code should be used: |
||
+ | |||
+ | <syntaxhighlight> |
||
+ | APTR mutex; |
||
+ | uint32 sigmask; |
||
+ | |||
+ | IExec->MutexAttemptWithSignal(mutex, sigmask); |
||
+ | </syntaxhighlight> |
Revision as of 21:24, 23 May 2012
Exec Mutexes
Mutexes are similar to Exec Semaphores although the protocol defined on them is much simpler.
Mutexes can not be obtained shared or in an asynchronous fashion. If these features are required then a semaphore will likely be necessary. However, if the mutex isn't locked when an attempt is made to obtain it, it will acquire the lock without the use of Forbid/Permit locking. This puts less overhead on the system as a whole so a mutex should be preferred over a semaphore in most cases.
A mutex is also opaque. This means the programmer is not allowed to see the internals of a mutex. The reason for this design choice is to make it possible for the system to be able to break deadlocks when necessary and free mutexes automatically. SignalSemaphores are not opaque and may also be allocated statically which makes it impossible for the system to safely break a deadlock or free a semaphore automatically.
A mutex may be recursive or not. A recursive mutex is one which allows the same task which obtained it to obtain it again. In most cases, a recursive mutex is what is required so the default is to create a recursive mutex.
For mutexes to work correctly, there are two restrictions that must be observed at all times:
- All tasks using shared data that is protected by a mutex must always ask for the mutex first before accessing the data. If some task accesses the data directly without first going through the mutex, the data may be corrupted. No task will have safe access to the data.
- A deadlock will occur if a task that owns a mutex on some data inadvertently calls another task which tries to get the mutex on that same data. Deadlocks and other such issues are beyond the scope of this manual. For more details on deadlocks and other problems of shared data in a multitasking system and the methods used to prevent them, refer to Wikipedia.
Creating a Mutex
There is only one way to create a Mutex and that is via the AllocSysObject() function with an object type of ASOT_MUTEX. The mutex is an opaque pointer taht is not open to the public.
Here is an example showing how to create a mutex:
APTR mutex = IExec->AllocSysObjectTags(ASOT_MUTEX, ASOMUTEX_Recursive, FALSE, // The default is to create a recursive mutex. TAG_END);
Obtaining a Mutex
The MutexObtain() function can be used to get a lock on a mutex. If another task currently has a lock on the mutex, your task will be put to sleep until all locks on the the mutex are released. If the same task tries to lock the mutex a second time the behaviour depends on whether the mutex was created with the recursive property or not.
Mutex Nesting. Mutexes have optional nesting. If the mutex is recursive, a lock by the same task on the same mutex will always succeed. If the mutex is not recursive, a lock by the same task on the same mutex will always fail. Which mode is most appropriate depends on the design of the application. |
To obtain a mutex use:
APTR mutex; IExec->MutexObtain(mutex);
Checking a Mutex
When you attempt to obtain a mutex with MutexObtain(), your task will be put to sleep if the mutex is not currently available. If you do not want to wait, you can call MutexAttempt(). If the mutex is available for locking, MutexAttempt() obtains it for you and returns TRUE. If it is not available, the function returns FALSE immediately instead of waiting for the mutex to be released.
The MutexAttemptWithSignal() function is similar to MutexAttempt() but will block if the mutex cannot be obtained. What makes MutexAttemptWithSignal() special is that it will unblock if the mutex is released or if a predefined signal is received. Being able to block on a mutex or a signal removes the need for any Forbid()/Permit() locking in such situations.
To attempt to obtain a mutex, use the following:
APTR mutex; IExec->MutexAttempt(mutex);
To make an attempt to obtain a mutex or a signal, the following code should be used:
APTR mutex; uint32 sigmask; IExec->MutexAttemptWithSignal(mutex, sigmask);