Mutex: Difference between revisions
Content added Content deleted
m (→{{header|J}}) |
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
||
Line 31: | Line 31: | ||
''Side note: During a 6502's NMI, other interrupts cannot occur, not even another NMI. Therefore there is no chance that an IRQ will happen while executing NMI code.'' |
''Side note: During a 6502's NMI, other interrupts cannot occur, not even another NMI. Therefore there is no chance that an IRQ will happen while executing NMI code.'' |
||
< |
<syntaxhighlight lang="6502asm">;assume that the NES's screen is active and NMI occurs at the end of every frame. |
||
mutex equ $01 ;these addresses in zero page memory will serve as the global variables. |
mutex equ $01 ;these addresses in zero page memory will serve as the global variables. |
||
Line 88: | Line 88: | ||
BEQ again ;this would loop infinitely if it weren't for vblankflag being set during NMI |
BEQ again ;this would loop infinitely if it weren't for vblankflag being set during NMI |
||
pla |
pla |
||
rts</ |
rts</syntaxhighlight> |
||
=={{header|8086 Assembly}}== |
=={{header|8086 Assembly}}== |
||
Line 95: | Line 95: | ||
* <code>LOCK</code> can't be placed in front of any instruction on the 8086, only ones where it actually applies. |
* <code>LOCK</code> can't be placed in front of any instruction on the 8086, only ones where it actually applies. |
||
< |
<syntaxhighlight lang="asm">lock inc word ptr [ds:TestData] ;increment the word at TestData. Only this CPU can access it right now. |
||
lock dec byte ptr [es:di]</ |
lock dec byte ptr [es:di]</syntaxhighlight> |
||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
Line 102: | Line 102: | ||
The mutex interface: |
The mutex interface: |
||
< |
<syntaxhighlight lang="ada">protected type Mutex is |
||
entry Seize; |
entry Seize; |
||
procedure Release; |
procedure Release; |
||
private |
private |
||
Owned : Boolean := False; |
Owned : Boolean := False; |
||
end Mutex;</ |
end Mutex;</syntaxhighlight> |
||
The implementation of: |
The implementation of: |
||
< |
<syntaxhighlight lang="ada">protected body Mutex is |
||
entry Seize when not Owned is |
entry Seize when not Owned is |
||
begin |
begin |
||
Line 118: | Line 118: | ||
Owned := False; |
Owned := False; |
||
end Release; |
end Release; |
||
end Mutex;</ |
end Mutex;</syntaxhighlight> |
||
Here the entry Seize has a queue of the [[task]]s waiting for the mutex. The entry's barrier is closed when Owned is true. So any task calling to the entry will be queued. When the barrier is open the first task from the queue executes the entry and Owned becomes true closing the barrier again. The procedure Release simply sets Owned to false. Both Seize and Release are protected actions whose execution causes reevaluation of all barriers, in this case one of Seize. |
Here the entry Seize has a queue of the [[task]]s waiting for the mutex. The entry's barrier is closed when Owned is true. So any task calling to the entry will be queued. When the barrier is open the first task from the queue executes the entry and Owned becomes true closing the barrier again. The procedure Release simply sets Owned to false. Both Seize and Release are protected actions whose execution causes reevaluation of all barriers, in this case one of Seize. |
||
Use: |
Use: |
||
< |
<syntaxhighlight lang="ada">declare |
||
M : Mutex; |
M : Mutex; |
||
begin |
begin |
||
Line 136: | Line 136: | ||
... -- Critical code |
... -- Critical code |
||
M.Release; -- Release the mutex |
M.Release; -- Release the mutex |
||
end;</ |
end;</syntaxhighlight> |
||
It is also possible to implement mutex as a monitor task. |
It is also possible to implement mutex as a monitor task. |
||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
< |
<syntaxhighlight lang="bbcbasic"> REM Create mutex: |
||
SYS "CreateMutex", 0, 0, 0 TO hMutex% |
SYS "CreateMutex", 0, 0, 0 TO hMutex% |
||
Line 153: | Line 153: | ||
REM Free mutex: |
REM Free mutex: |
||
SYS "CloseHandle", hMutex%</ |
SYS "CloseHandle", hMutex%</syntaxhighlight> |
||
=={{header|C}}== |
=={{header|C}}== |
||
Line 160: | Line 160: | ||
{{works with|Win32}} |
{{works with|Win32}} |
||
To create a mutex operating system "object": |
To create a mutex operating system "object": |
||
< |
<syntaxhighlight lang="c">HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);</syntaxhighlight> |
||
To lock the mutex: |
To lock the mutex: |
||
<lang |
<syntaxhighlight lang="c">WaitForSingleObject(hMutex, INFINITE);</syntaxhighlight> |
||
To unlock the mutex |
To unlock the mutex |
||
<lang |
<syntaxhighlight lang="c">ReleaseMutex(hMutex);</syntaxhighlight> |
||
When the program is finished with the mutex: |
When the program is finished with the mutex: |
||
<lang |
<syntaxhighlight lang="c">CloseHandle(hMutex);</syntaxhighlight> |
||
===POSIX=== |
===POSIX=== |
||
Line 173: | Line 173: | ||
Creating a mutex: |
Creating a mutex: |
||
< |
<syntaxhighlight lang="c">#include <pthread.h> |
||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;</ |
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;</syntaxhighlight> |
||
Or: |
Or: |
||
< |
<syntaxhighlight lang="c">pthread_mutex_t mutex; |
||
pthread_mutex_init(&mutex, NULL);</ |
pthread_mutex_init(&mutex, NULL);</syntaxhighlight> |
||
Locking: |
Locking: |
||
< |
<syntaxhighlight lang="c">int error = pthread_mutex_lock(&mutex);</syntaxhighlight> |
||
Unlocking: |
Unlocking: |
||
< |
<syntaxhighlight lang="c">int error = pthread_mutex_unlock(&mutex);</syntaxhighlight> |
||
Trying to lock (but do not wait if it can't) |
Trying to lock (but do not wait if it can't) |
||
< |
<syntaxhighlight lang="c">int error = pthread_mutex_trylock(&mutex);</syntaxhighlight> |
||
=={{header|C++}}== |
=={{header|C++}}== |
||
Line 205: | Line 205: | ||
=={{header|D}}== |
=={{header|D}}== |
||
<syntaxhighlight lang="d"> |
|||
<lang d> |
|||
class Synced |
class Synced |
||
{ |
{ |
||
Line 217: | Line 217: | ||
static num = 0; |
static num = 0; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Keep in mind that '''synchronized''' used as above works on a per-class-instance basis. |
Keep in mind that '''synchronized''' used as above works on a per-class-instance basis. |
||
Line 223: | Line 223: | ||
The following example tries to illustrate the problem: |
The following example tries to illustrate the problem: |
||
< |
<syntaxhighlight lang="d">import tango.core.Thread, tango.io.Stdout, tango.util.log.Trace; |
||
class Synced { |
class Synced { |
||
Line 268: | Line 268: | ||
tested.func(d_id); |
tested.func(d_id); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Every created thread creates its own '''Synced''' object, and because the monitor created by synchronized statement is created for every object, |
Every created thread creates its own '''Synced''' object, and because the monitor created by synchronized statement is created for every object, |
||
Line 276: | Line 276: | ||
like here: |
like here: |
||
<syntaxhighlight lang="d"> |
|||
<lang D> |
|||
class Synced { |
class Synced { |
||
public int func (int input) { |
public int func (int input) { |
||
Line 288: | Line 288: | ||
private static int foo; |
private static int foo; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Delphi}}== |
=={{header|Delphi}}== |
||
{{libheader| Winapi.Windows}} |
{{libheader| Winapi.Windows}} |
||
Line 297: | Line 297: | ||
{{libheader| System.SyncObjs}} |
{{libheader| System.SyncObjs}} |
||
{{libheader| Vcl.StdCtrls}} |
{{libheader| Vcl.StdCtrls}} |
||
<syntaxhighlight lang="delphi"> |
|||
<lang Delphi> |
|||
unit main; |
unit main; |
||
Line 392: | Line 392: | ||
end; |
end; |
||
end.</ |
end.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Thread 1 |
<pre>Thread 1 |
||
Line 402: | Line 402: | ||
E's approach to concurrency is to ''never'' block, in favor of message passing/event queues/callbacks. Therefore, it is unidiomatic to use a mutex at all, and incorrect, or rather ''unsafe'', to use a mutex which blocks the calling thread. That said, here is a mutex written in E. |
E's approach to concurrency is to ''never'' block, in favor of message passing/event queues/callbacks. Therefore, it is unidiomatic to use a mutex at all, and incorrect, or rather ''unsafe'', to use a mutex which blocks the calling thread. That said, here is a mutex written in E. |
||
< |
<syntaxhighlight lang="e">def makeMutex() { |
||
# The mutex is available (released) if available is resolved, otherwise it |
# The mutex is available (released) if available is resolved, otherwise it |
||
Line 417: | Line 417: | ||
} |
} |
||
return mutex |
return mutex |
||
}</ |
}</syntaxhighlight> |
||
This implementation of a mutex is designed to have a very short implementation as well as usage in E. The mutex object is a function which takes a function ''action'' to be executed once the mutex is available. The mutex is unavailable until the return value of ''action'' resolves. This interface has been chosen over lock and unlock operations to reduce the hazard of unbalanced lock/unlock pairs, and because it naturally fits into E code. |
This implementation of a mutex is designed to have a very short implementation as well as usage in E. The mutex object is a function which takes a function ''action'' to be executed once the mutex is available. The mutex is unavailable until the return value of ''action'' resolves. This interface has been chosen over lock and unlock operations to reduce the hazard of unbalanced lock/unlock pairs, and because it naturally fits into E code. |
||
Line 423: | Line 423: | ||
Usage example: |
Usage example: |
||
< |
<syntaxhighlight lang="e">Creating the mutex: |
||
? def mutex := makeMutex() |
? def mutex := makeMutex() |
||
Line 461: | Line 461: | ||
? value |
? value |
||
# value: 2</ |
# value: 2</syntaxhighlight> |
||
<code>when</code> blocks and <code>Ref.whenResolved</code> return a ''promise'' for the result of the deferred action, so the mutex here waits for the gratuitously complicated increment to complete before becoming available for the next action. |
<code>when</code> blocks and <code>Ref.whenResolved</code> return a ''promise'' for the result of the deferred action, so the mutex here waits for the gratuitously complicated increment to complete before becoming available for the next action. |
||
Line 467: | Line 467: | ||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
Erlang has no mutexes so this is a super simple one, hand built to allow 3 slowly printing processes to print until done before the next one starts. |
Erlang has no mutexes so this is a super simple one, hand built to allow 3 slowly printing processes to print until done before the next one starts. |
||
<syntaxhighlight lang="erlang"> |
|||
<lang Erlang> |
|||
-module( mutex ). |
-module( mutex ). |
||
Line 508: | Line 508: | ||
io:fwrite( " ~p", [X] ), |
io:fwrite( " ~p", [X] ), |
||
timer:sleep( 100 ). |
timer:sleep( 100 ). |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 529: | Line 529: | ||
MutexCreate, MutexLock, MutexUnlock, MutexDestroy and ThreadCreate. |
MutexCreate, MutexLock, MutexUnlock, MutexDestroy and ThreadCreate. |
||
< |
<syntaxhighlight lang="freebasic">' Threading synchronization using Mutexes |
||
' If you comment out the lines containing "MutexLock" and "MutexUnlock", the |
' If you comment out the lines containing "MutexLock" and "MutexUnlock", the |
||
' threads will not be in sync and some of the data may be printed out of place. |
' threads will not be in sync and some of the data may be printed out of place. |
||
Line 582: | Line 582: | ||
' Clean up when finished |
' Clean up when finished |
||
Mutexdestroy(bloqueo_tty) |
Mutexdestroy(bloqueo_tty) |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
Line 589: | Line 589: | ||
{{trans|E}} |
{{trans|E}} |
||
Go has mutexes, and here is an example use of a mutex, somewhat following the example of E. This code defines a slow incrementer, that reads a variable, then a significant amount of time later, writes an incremented value back to the variable. Two incrementers are started concurrently. Without the mutex, one would overwrite the other and the result would be 1. Using a mutex, as shown here, one waits for the other and the result is 2. |
Go has mutexes, and here is an example use of a mutex, somewhat following the example of E. This code defines a slow incrementer, that reads a variable, then a significant amount of time later, writes an incremented value back to the variable. Two incrementers are started concurrently. Without the mutex, one would overwrite the other and the result would be 1. Using a mutex, as shown here, one waits for the other and the result is 2. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 616: | Line 616: | ||
wg.Wait() |
wg.Wait() |
||
fmt.Println(value) |
fmt.Println(value) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 628: | Line 628: | ||
As soon as things start getting complicated though, Go channels offer a much clearer alternative. |
As soon as things start getting complicated though, Go channels offer a much clearer alternative. |
||
As a gateway from mutexes to channels, here is the above program implemented with channels: |
As a gateway from mutexes to channels, here is the above program implemented with channels: |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 667: | Line 667: | ||
<-done |
<-done |
||
fmt.Println(value) |
fmt.Println(value) |
||
}</ |
}</syntaxhighlight> |
||
The value passed on the channel is not accessed here, just as the internal state of a mutex is not accessed. Rather, it is only the effect of the value being available that is important. (Of course if you wanted to send something meaningful on the channel, a reference to the shared resource would be a good start...) |
The value passed on the channel is not accessed here, just as the internal state of a mutex is not accessed. Rather, it is only the effect of the value being available that is important. (Of course if you wanted to send something meaningful on the channel, a reference to the shared resource would be a good start...) |
||
Line 673: | Line 673: | ||
Haskell has a slight variation on the mutex, namely the MVar. MVars, unlike mutexes, are containers. However, they are similar enough that MVar () is essentially a mutex. A MVar can be in two states: empty or full, only storing a value when full. There are 4 main ways to deal with MVars: |
Haskell has a slight variation on the mutex, namely the MVar. MVars, unlike mutexes, are containers. However, they are similar enough that MVar () is essentially a mutex. A MVar can be in two states: empty or full, only storing a value when full. There are 4 main ways to deal with MVars: |
||
< |
<syntaxhighlight lang="haskell">takeMVar :: MVar a -> IO a |
||
putMVar :: MVar a -> a -> IO () |
putMVar :: MVar a -> a -> IO () |
||
tryTakeMVar :: MVar a -> IO (Maybe a) |
tryTakeMVar :: MVar a -> IO (Maybe a) |
||
tryPutMVar :: MVar a -> a -> IO Bool |
tryPutMVar :: MVar a -> a -> IO Bool |
||
</syntaxhighlight> |
|||
</lang> |
|||
takeMVar will attempt to fetch a value from the MVar, and will block while the MVar is empty. After using this, the MVar will be left empty. |
takeMVar will attempt to fetch a value from the MVar, and will block while the MVar is empty. After using this, the MVar will be left empty. |
||
Line 688: | Line 688: | ||
The following code uses features exclusive to Unicon. |
The following code uses features exclusive to Unicon. |
||
<syntaxhighlight lang="unicon"> |
|||
<lang Unicon> |
|||
x: = mutex() # create and return a mutex handle for sharing between threads needing to synchronize with each other |
x: = mutex() # create and return a mutex handle for sharing between threads needing to synchronize with each other |
||
Line 698: | Line 698: | ||
unlock(x) # unlock mutex x |
unlock(x) # unlock mutex x |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
Line 706: | Line 706: | ||
Note: currently J mutexes do not have a meaningful display representation. |
Note: currently J mutexes do not have a meaningful display representation. |
||
< |
<syntaxhighlight lang="j"> name=. 10 T. 0 NB. create an exclusive mutex |
||
name=. 10 T. 1 NB. create a shared (aka "recursive" or "reentrant") mutex |
name=. 10 T. 1 NB. create a shared (aka "recursive" or "reentrant") mutex |
||
failed=. 11 T. mutex NB. take an exclusive lock on a mutex (waiting forever if necessary) |
failed=. 11 T. mutex NB. take an exclusive lock on a mutex (waiting forever if necessary) |
||
failed=. 11 T. mutex;seconds NB. try to take an exclusive lock on a mutex but may time out |
failed=. 11 T. mutex;seconds NB. try to take an exclusive lock on a mutex but may time out |
||
NB. failed is 0 if lock was taken, 1 if lock was not taken |
NB. failed is 0 if lock was taken, 1 if lock was not taken |
||
13 T. mutex NB. release lock on mutex</ |
13 T. mutex NB. release lock on mutex</syntaxhighlight> |
||
Recursive mutexes may be locked multiple times -- successive locks increase a counter. When unlocked as many times as previously locked, the mutex is released. |
Recursive mutexes may be locked multiple times -- successive locks increase a counter. When unlocked as many times as previously locked, the mutex is released. |
||
Line 721: | Line 721: | ||
Java 5 added a <code>Semaphore</code> class which can act as a mutex (as stated above, a mutex is "a variant of semaphore with ''k''=1"). |
Java 5 added a <code>Semaphore</code> class which can act as a mutex (as stated above, a mutex is "a variant of semaphore with ''k''=1"). |
||
< |
<syntaxhighlight lang="java5">import java.util.concurrent.Semaphore; |
||
public class VolatileClass{ |
public class VolatileClass{ |
||
Line 730: | Line 730: | ||
} |
} |
||
//delegate methods could be added for acquiring and releasing the mutex |
//delegate methods could be added for acquiring and releasing the mutex |
||
}</ |
}</syntaxhighlight> |
||
Using the mutex: |
Using the mutex: |
||
< |
<syntaxhighlight lang="java5">public class TestVolitileClass throws Exception{ |
||
public static void main(String[] args){ |
public static void main(String[] args){ |
||
VolatileClass vc = new VolatileClass(); |
VolatileClass vc = new VolatileClass(); |
||
Line 741: | Line 741: | ||
vc.mutex.release(); |
vc.mutex.release(); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Java also has the synchronized keyword, which allows almost any object to be used to enforce mutual exclusion. |
Java also has the synchronized keyword, which allows almost any object to be used to enforce mutual exclusion. |
||
< |
<syntaxhighlight lang="java">public class Main { |
||
static Object mutex = new Object(); |
static Object mutex = new Object(); |
||
static int i = 0; |
static int i = 0; |
||
Line 779: | Line 779: | ||
}.start(); |
}.start(); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
The "synchronized" keyword actually is a form of [[monitor]], which was a later-proposed solution to the same problems that mutexes and semaphores were designed to solve. More about synchronization may be found on Sun's website - http://java.sun.com/docs/books/tutorial/essential/concurrency/sync.html , and more about monitors may be found in any decent operating systems textbook. |
The "synchronized" keyword actually is a form of [[monitor]], which was a later-proposed solution to the same problems that mutexes and semaphores were designed to solve. More about synchronization may be found on Sun's website - http://java.sun.com/docs/books/tutorial/essential/concurrency/sync.html , and more about monitors may be found in any decent operating systems textbook. |
||
Line 786: | Line 786: | ||
From the Julia documentation: |
From the Julia documentation: |
||
<lang |
<syntaxhighlight lang="julia">SpinLock()</syntaxhighlight> |
||
Create a non-reentrant lock. Recursive use will result in a deadlock. Each lock must be matched with an unlock. |
Create a non-reentrant lock. Recursive use will result in a deadlock. Each lock must be matched with an unlock. |
||
<lang |
<syntaxhighlight lang="julia">lock(lock)</syntaxhighlight> |
||
Acquire the lock when it becomes available. If the lock is already locked by a different task/thread, wait for it to become available. |
Acquire the lock when it becomes available. If the lock is already locked by a different task/thread, wait for it to become available. |
||
Line 795: | Line 795: | ||
Each lock must be matched by an unlock. |
Each lock must be matched by an unlock. |
||
<lang |
<syntaxhighlight lang="julia">unlock(lock)</syntaxhighlight> |
||
Releases ownership of the lock. |
Releases ownership of the lock. |
||
If this is a recursive lock which has been acquired before, decrement an internal counter and return immediately. |
If this is a recursive lock which has been acquired before, decrement an internal counter and return immediately. |
||
<lang |
<syntaxhighlight lang="julia">trylock(lock)</syntaxhighlight> |
||
Acquire the lock if it is available, and return true if successful. If the lock is already locked by a different task/thread, return false. |
Acquire the lock if it is available, and return true if successful. If the lock is already locked by a different task/thread, return false. |
||
Each successful trylock must be matched by an unlock. |
Each successful trylock must be matched by an unlock. |
||
<lang |
<syntaxhighlight lang="julia">islocked(lock)</syntaxhighlight> |
||
Check whether the lock is held by any task/thread. This should not be used for synchronization (see instead trylock). |
Check whether the lock is held by any task/thread. This should not be used for synchronization (see instead trylock). |
||
<lang |
<syntaxhighlight lang="julia">ReentrantLock()</syntaxhighlight> |
||
Creates a re-entrant lock for synchronizing Tasks. The same task can acquire the lock as many times as required. Each lock must be matched with an unlock. |
Creates a re-entrant lock for synchronizing Tasks. The same task can acquire the lock as many times as required. Each lock must be matched with an unlock. |
||
=={{header|Logtalk}}== |
=={{header|Logtalk}}== |
||
Logtalk provides a synchronized/0 directive for synchronizing all object (or category) predicates using the same implicit mutex and a synchronized/1 directive for synchronizing a set of predicates using the same implicit mutex. Follow an usage example of the synchronized/1 directive (inspired by the Erlang example). Works when using SWI-Prolog, XSB, or YAP as the backend compiler. |
Logtalk provides a synchronized/0 directive for synchronizing all object (or category) predicates using the same implicit mutex and a synchronized/1 directive for synchronizing a set of predicates using the same implicit mutex. Follow an usage example of the synchronized/1 directive (inspired by the Erlang example). Works when using SWI-Prolog, XSB, or YAP as the backend compiler. |
||
< |
<syntaxhighlight lang="logtalk"> |
||
:- object(slow_print). |
:- object(slow_print). |
||
Line 847: | Line 847: | ||
:- end_object. |
:- end_object. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 867: | Line 867: | ||
Using concurrent (in interpreter level), after the execution of one statement, thread change. Using Sequential each thread block run all statements, until end, or leave some if a continue take place. In concurrent also a call to a module, or executing a block of code happen without in one thread. |
Using concurrent (in interpreter level), after the execution of one statement, thread change. Using Sequential each thread block run all statements, until end, or leave some if a continue take place. In concurrent also a call to a module, or executing a block of code happen without in one thread. |
||
<syntaxhighlight lang="m2000 interpreter"> |
|||
<lang M2000 Interpreter> |
|||
Form 80, 50 |
Form 80, 50 |
||
Module CheckIt { |
Module CheckIt { |
||
Line 923: | Line 923: | ||
} |
} |
||
CheckIt |
CheckIt |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
Line 930: | Line 930: | ||
Creating a mutex: |
Creating a mutex: |
||
< |
<syntaxhighlight lang="nim">import locks |
||
var mutex: Lock |
var mutex: Lock |
||
initLock mutex</ |
initLock mutex</syntaxhighlight> |
||
Locking: |
Locking: |
||
<lang |
<syntaxhighlight lang="nim">acquire mutex</syntaxhighlight> |
||
Unlocking: |
Unlocking: |
||
<lang |
<syntaxhighlight lang="nim">release mutex</syntaxhighlight> |
||
# Trying to lock (but do not wait if it can't) |
# Trying to lock (but do not wait if it can't) |
||
< |
<syntaxhighlight lang="nim">let success = tryAcquire mutex</syntaxhighlight> |
||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
||
Objeck provides a simple way to lock a section of code. Please refer to the [[Objeck|programer's guide]] for addition information. |
Objeck provides a simple way to lock a section of code. Please refer to the [[Objeck|programer's guide]] for addition information. |
||
< |
<syntaxhighlight lang="objeck"> |
||
m := ThreadMutex->New("lock a"); |
m := ThreadMutex->New("lock a"); |
||
# section locked |
# section locked |
||
Line 951: | Line 951: | ||
} |
} |
||
# section unlocked |
# section unlocked |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
< |
<syntaxhighlight lang="objc">NSLock *m = [[NSLock alloc] init]; |
||
[m lock]; // locks in blocking mode |
[m lock]; // locks in blocking mode |
||
Line 965: | Line 965: | ||
} |
} |
||
[m unlock];</ |
[m unlock];</syntaxhighlight> |
||
Reentrant mutex is provided by the <tt>NSRecursiveLock</tt> class. |
Reentrant mutex is provided by the <tt>NSRecursiveLock</tt> class. |
||
Line 976: | Line 976: | ||
It is very simple, there are four functions: |
It is very simple, there are four functions: |
||
< |
<syntaxhighlight lang="ocaml">let m = Mutex.create() in |
||
Mutex.lock m; (* locks in blocking mode *) |
Mutex.lock m; (* locks in blocking mode *) |
||
Line 983: | Line 983: | ||
else ... (* already locked, do not block *) |
else ... (* already locked, do not block *) |
||
Mutex.unlock m;</ |
Mutex.unlock m;</syntaxhighlight> |
||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
Line 992: | Line 992: | ||
If the channel is empty, a task will wait until an object is available into the channel. |
If the channel is empty, a task will wait until an object is available into the channel. |
||
< |
<syntaxhighlight lang="oforth">import: parallel |
||
: job(mut) |
: job(mut) |
||
Line 1,004: | Line 1,004: | ||
| mut | |
| mut | |
||
Channel new dup send(1) drop ->mut |
Channel new dup send(1) drop ->mut |
||
10 #[ #[ mut job ] & ] times ;</ |
10 #[ #[ mut job ] & ] times ;</syntaxhighlight> |
||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
Line 1,010: | Line 1,010: | ||
Creating a mutex: |
Creating a mutex: |
||
< |
<syntaxhighlight lang="oz">declare L = {Lock.new}</syntaxhighlight> |
||
The only way to acquire a mutex is to use the <code>lock</code> syntax. This ensures that releasing a lock can never be forgotten. Even if an exception occurs, the lock will be released. |
The only way to acquire a mutex is to use the <code>lock</code> syntax. This ensures that releasing a lock can never be forgotten. Even if an exception occurs, the lock will be released. |
||
< |
<syntaxhighlight lang="oz">lock L then |
||
{System.show exclusive} |
{System.show exclusive} |
||
end</ |
end</syntaxhighlight> |
||
To make it easier to work with objects, classes can be marked with the property <code>locking</code>. Instances of such classes have their own internal lock and can use a variant of the <code>lock</code> syntax: |
To make it easier to work with objects, classes can be marked with the property <code>locking</code>. Instances of such classes have their own internal lock and can use a variant of the <code>lock</code> syntax: |
||
< |
<syntaxhighlight lang="oz">class Test |
||
prop locking |
prop locking |
||
Line 1,026: | Line 1,026: | ||
end |
end |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Code demonstrating shared resources and simple locking. Resource1 and Resource2 represent some limited resources that must be exclusively used and released by each thread. Each thread reports how many of each is available; if it goes below zero, something is wrong. Try comment out either of the "lock $lock*" line to see what happens without locking. |
Code demonstrating shared resources and simple locking. Resource1 and Resource2 represent some limited resources that must be exclusively used and released by each thread. Each thread reports how many of each is available; if it goes below zero, something is wrong. Try comment out either of the "lock $lock*" line to see what happens without locking. |
||
< |
<syntaxhighlight lang="perl">use Thread qw'async'; |
||
use threads::shared; |
use threads::shared; |
||
Line 1,057: | Line 1,057: | ||
for ( map async{ use_resource }, 1 .. 9) { |
for ( map async{ use_resource }, 1 .. 9) { |
||
$_->join |
$_->join |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
=== local mutexes === |
=== local mutexes === |
||
Exclusive-only and non-reentrant. |
Exclusive-only and non-reentrant. |
||
<!--< |
<!--<syntaxhighlight lang="phix">(notonline)--> |
||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (critical sections)</span> |
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (critical sections)</span> |
||
<span style="color: #004080;">integer</span> <span style="color: #000000;">cs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">()</span> <span style="color: #000080;font-style:italic;">-- Create a new critical section</span> |
<span style="color: #004080;">integer</span> <span style="color: #000000;">cs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_cs</span><span style="color: #0000FF;">()</span> <span style="color: #000080;font-style:italic;">-- Create a new critical section</span> |
||
Line 1,071: | Line 1,071: | ||
<span style="color: #0000FF;">...</span> |
<span style="color: #0000FF;">...</span> |
||
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cs</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- Delete a critical section that you have no further use for</span> |
<span style="color: #000000;">delete_cs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cs</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- Delete a critical section that you have no further use for</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
=== global mutexes === |
=== global mutexes === |
||
Using file locking. Only shared locks are reentrant. Every call needs it's own bespoke retry logic. There is no builtin promotion operation. |
Using file locking. Only shared locks are reentrant. Every call needs it's own bespoke retry logic. There is no builtin promotion operation. |
||
<!--< |
<!--<syntaxhighlight lang="phix">(notonline)--> |
||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o)</span> |
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o)</span> |
||
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"log.txt"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"u"</span><span style="color: #0000FF;">),</span> |
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"log.txt"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"u"</span><span style="color: #0000FF;">),</span> |
||
Line 1,091: | Line 1,091: | ||
<span style="color: #0000FF;">...</span> |
<span style="color: #0000FF;">...</span> |
||
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span> |
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
Line 1,110: | Line 1,110: | ||
To create a global mutex: |
To create a global mutex: |
||
< |
<syntaxhighlight lang="prolog">mutex_create(Mutex, [alias(my_mutex)]).</syntaxhighlight> |
||
The recommended way to use the mutex is by wrapping code in a with_mutex/2 call, eg: |
The recommended way to use the mutex is by wrapping code in a with_mutex/2 call, eg: |
||
< |
<syntaxhighlight lang="prolog">synchronized_goal(G) :- with_mutex(my_mutex, call(G)).</syntaxhighlight> |
||
This will wrap some code in a mutex to ensure exclusive access and release the mutex on completion (regardless or the result). |
This will wrap some code in a mutex to ensure exclusive access and release the mutex on completion (regardless or the result). |
||
Line 1,120: | Line 1,120: | ||
'''PureBasic has the following Mutex functions;''' |
'''PureBasic has the following Mutex functions;''' |
||
< |
<syntaxhighlight lang="purebasic">MyMutex=CreateMutex() |
||
Result = TryLockMutex(MyMutex) |
Result = TryLockMutex(MyMutex) |
||
LockMutex(MyMutex) |
LockMutex(MyMutex) |
||
UnlockMutex(MyMutex) |
UnlockMutex(MyMutex) |
||
FreeMutex(MyMutex)</ |
FreeMutex(MyMutex)</syntaxhighlight> |
||
'''Example''' |
'''Example''' |
||
< |
<syntaxhighlight lang="purebasic">Declare ThreadedTask(*MyArgument) |
||
Define Mutex |
Define Mutex |
||
Line 1,160: | Line 1,160: | ||
UnlockMutex(Mutex) |
UnlockMutex(Mutex) |
||
Next |
Next |
||
EndProcedure</ |
EndProcedure</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
Line 1,168: | Line 1,168: | ||
a semaphore grants access to a number of threads up to certain value. |
a semaphore grants access to a number of threads up to certain value. |
||
< |
<syntaxhighlight lang="python">import threading |
||
from time import sleep |
from time import sleep |
||
Line 1,197: | Line 1,197: | ||
for i in range(1, 5): |
for i in range(1, 5): |
||
t = res_thread() |
t = res_thread() |
||
t.start()</ |
t.start()</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Line 1,203: | Line 1,203: | ||
Racket has semaphores which can be used as mutexes in the usual way. |
Racket has semaphores which can be used as mutexes in the usual way. |
||
With other language features this can be used to implement new features -- for example, here is how we would implement a protected-by-a-mutex function: |
With other language features this can be used to implement new features -- for example, here is how we would implement a protected-by-a-mutex function: |
||
< |
<syntaxhighlight lang="racket"> |
||
(define foo |
(define foo |
||
(let ([sema (make-semaphore 1)]) |
(let ([sema (make-semaphore 1)]) |
||
Line 1,209: | Line 1,209: | ||
(dynamic-wind (λ() (semaphore-wait sema)) |
(dynamic-wind (λ() (semaphore-wait sema)) |
||
(λ() (... do something ...)) |
(λ() (... do something ...)) |
||
(λ() (semaphore-post sema))))))</ |
(λ() (semaphore-post sema))))))</syntaxhighlight> |
||
and it is now easy to turn this into a macro for definitions of such functions: |
and it is now easy to turn this into a macro for definitions of such functions: |
||
< |
<syntaxhighlight lang="racket"> |
||
(define-syntax-rule (define/atomic (name arg ...) E ...) |
(define-syntax-rule (define/atomic (name arg ...) E ...) |
||
(define name |
(define name |
||
Line 1,221: | Line 1,221: | ||
;; this does the same as the above now: |
;; this does the same as the above now: |
||
(define/atomic (foo x) |
(define/atomic (foo x) |
||
(... do something ...))</ |
(... do something ...))</syntaxhighlight> |
||
But more than just linguistic features, Racket has many additional synchronization tools in its VM. |
But more than just linguistic features, Racket has many additional synchronization tools in its VM. |
||
Line 1,229: | Line 1,229: | ||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
(formerly Perl 6) |
(formerly Perl 6) |
||
<lang |
<syntaxhighlight lang="raku" line>my $lock = Lock.new; |
||
$lock.protect: { your-ad-here() }</ |
$lock.protect: { your-ad-here() }</syntaxhighlight> |
||
Locks are reentrant. You may explicitly lock and unlock them, but the syntax above guarantees the lock will be unlocked on scope exit, even if by thrown exception or other exotic control flow. That being said, direct use of locks is discouraged in Perl 6 in favor of promises, channels, and supplies, which offer better composable semantics. |
Locks are reentrant. You may explicitly lock and unlock them, but the syntax above guarantees the lock will be unlocked on scope exit, even if by thrown exception or other exotic control flow. That being said, direct use of locks is discouraged in Perl 6 in favor of promises, channels, and supplies, which offer better composable semantics. |
||
Line 1,237: | Line 1,237: | ||
Ruby's standard library includes a <tt>mutex_m</tt> module that can be mixed-in |
Ruby's standard library includes a <tt>mutex_m</tt> module that can be mixed-in |
||
to a class. |
to a class. |
||
< |
<syntaxhighlight lang="ruby">require 'mutex_m' |
||
class SomethingWithMutex |
class SomethingWithMutex |
||
include Mutex_m |
include Mutex_m |
||
... |
... |
||
end</ |
end</syntaxhighlight> |
||
Individual objects can be extended with the module too |
Individual objects can be extended with the module too |
||
< |
<syntaxhighlight lang="ruby">an_object = Object.new |
||
an_object.extend(Mutex_m)</ |
an_object.extend(Mutex_m)</syntaxhighlight> |
||
An object with mutex powers can then: |
An object with mutex powers can then: |
||
< |
<syntaxhighlight lang="ruby"># acquire a lock -- block execution until it becomes free |
||
an_object.mu_lock |
an_object.mu_lock |
||
Line 1,264: | Line 1,264: | ||
an_object.my_synchronize do |
an_object.my_synchronize do |
||
do critical stuff |
do critical stuff |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
Line 1,274: | Line 1,274: | ||
append to a shared string. |
append to a shared string. |
||
< |
<syntaxhighlight lang="rust">use std::{ |
||
sync::{Arc, Mutex}, |
sync::{Arc, Mutex}, |
||
thread, |
thread, |
||
Line 1,316: | Line 1,316: | ||
shared.lock().ok().map_or((), |it| println!("Done: {}", it)); |
shared.lock().ok().map_or((), |it| println!("Done: {}", it)); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Shale}}== |
=={{header|Shale}}== |
||
Shale includes a library that provides POSIX threads, semaphores and mutexes. Below is a really simple example usings threads and one mutex. There's a more complete example that includes semaphores available with the [https://github.com/sharkshead/shale Shale source code]. |
Shale includes a library that provides POSIX threads, semaphores and mutexes. Below is a really simple example usings threads and one mutex. There's a more complete example that includes semaphores available with the [https://github.com/sharkshead/shale Shale source code]. |
||
< |
<syntaxhighlight lang="shale">#!/usr/local/bin/shale |
||
thread library // POSIX threads, mutexes and semaphores |
thread library // POSIX threads, mutexes and semaphores |
||
Line 1,350: | Line 1,350: | ||
// Wait a bit to let the threads do their stuff. |
// Wait a bit to let the threads do their stuff. |
||
1000 sleep time::() // milliseconds</ |
1000 sleep time::() // milliseconds</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,362: | Line 1,362: | ||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Tcl's [http://tcl.cvs.sourceforge.net/*checkout*/tcl/thread/doc/html/thread.html#19 mutexes] have four functions. |
Tcl's [http://tcl.cvs.sourceforge.net/*checkout*/tcl/thread/doc/html/thread.html#19 mutexes] have four functions. |
||
< |
<syntaxhighlight lang="tcl">package require Thread |
||
# How to create a mutex |
# How to create a mutex |
||
Line 1,374: | Line 1,374: | ||
# Dispose of the mutex |
# Dispose of the mutex |
||
thread::mutex destroy $m</ |
thread::mutex destroy $m</syntaxhighlight> |
||
There are also read-write mutexes available. |
There are also read-write mutexes available. |
||
< |
<syntaxhighlight lang="tcl">set rw [thread::rwmutex create] |
||
# Get and drop a reader lock |
# Get and drop a reader lock |
||
Line 1,386: | Line 1,386: | ||
thread::rwmutex unlock $rw |
thread::rwmutex unlock $rw |
||
thread::rwmutex destroy $rw</ |
thread::rwmutex destroy $rw</syntaxhighlight> |
||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
Line 1,395: | Line 1,395: | ||
However, to avoid excessive latency, a VM whose thread were continuing would need to signal to the host that it no longer needed the resource so the lock could be released thereby making it available to the other VM(s). Typically, a shared resource might need to be represented something like this in a Wren script: |
However, to avoid excessive latency, a VM whose thread were continuing would need to signal to the host that it no longer needed the resource so the lock could be released thereby making it available to the other VM(s). Typically, a shared resource might need to be represented something like this in a Wren script: |
||
< |
<syntaxhighlight lang="ecmascript">foreign class Resource { |
||
// obtain a pointer to the resource when available |
// obtain a pointer to the resource when available |
||
construct new() {} |
construct new() {} |
||
Line 1,408: | Line 1,408: | ||
var res = Resource.new() // wait for and obtain a lock on the resource |
var res = Resource.new() // wait for and obtain a lock on the resource |
||
res.doSomething() // use it |
res.doSomething() // use it |
||
res.release() // release the lock</ |
res.release() // release the lock</syntaxhighlight> |
||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
zkl has two mutex objects, Lock (mutex) and WriteLock a mutex that allows multiple readers but only one writer. |
zkl has two mutex objects, Lock (mutex) and WriteLock a mutex that allows multiple readers but only one writer. |
||
The critical keyword fences code to ensure the lock is released when the code is done. |
The critical keyword fences code to ensure the lock is released when the code is done. |
||
< |
<syntaxhighlight lang="zkl">var lock=Atomic.Lock(); lock.acquire(); doSomething(); lock.release(); |
||
critical(lock){ doSomething(); }</ |
critical(lock){ doSomething(); }</syntaxhighlight> |
||
< |
<syntaxhighlight lang="zkl">var lock=Atomic.WriteLock(); |
||
lock.acquireForReading(); doSomeReading(); lock.readerRelease(); |
lock.acquireForReading(); doSomeReading(); lock.readerRelease(); |
||
critical(lock,acquireForReading,readerRelease){ ... } |
critical(lock,acquireForReading,readerRelease){ ... } |
||
lock.acquireForWriting(); write(); lock.writerRelease();</ |
lock.acquireForWriting(); write(); lock.writerRelease();</syntaxhighlight> |
||
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have user-defined data structures or objects. --> |
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have user-defined data structures or objects. --> |