Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

6
Task/Mutex/00-META.yaml Normal file
View file

@ -0,0 +1,6 @@
---
category:
- Encyclopedia
from: http://rosettacode.org/wiki/Mutex
requires:
- Concurrency

23
Task/Mutex/00-TASK.txt Normal file
View file

@ -0,0 +1,23 @@
A '''mutex''' (''abbreviated'' '''Mut'''ually '''Ex'''clusive access) is a synchronization object, a variant of [[semaphore]] with ''k''=1.
A mutex is said to be seized by a [[task]] decreasing ''k''.
It is released when the task restores ''k''. Mutexes are typically used to protect a shared resource from concurrent access.
A [[task]] seizes (or acquires) the mutex, then accesses the resource, and after that releases the mutex.
A mutex is a low-level synchronization primitive exposed to deadlocking. A deadlock can occur with just two tasks and two mutexes (if each task attempts to acquire both mutexes, but in the opposite order).
Entering the deadlock is usually aggravated by a [[race condition]] state, which leads to sporadic hangups, which are very difficult to track down.
=Variants of mutexes=
==Global and local mutexes==
Usually the [[OS]] provides various implementations of mutexes corresponding to the variants of [[task]]s available in the OS. For example, system-wide mutexes can be used by [[process]]es. Local mutexes can be used only by [[threads]] etc. This distinction is maintained because, depending on the hardware, seizing a global mutex might be a thousand times slower than seizing a local one.
==Reentrant mutex==
A reentrant mutex can be seized by the same [[task]] multiple times. Each seizing of the mutex is matched by releasing it, in order to allow another task to seize it.
==Read write mutex==
A read write mutex can be seized at two levels for ''read'' and for ''write''. The mutex can be seized for ''read'' by any number of tasks. Only one task may seize it for '''write''. Read write mutexes are usually used to protect resources which can be accessed in mutable and immutable ways. Immutable (read) access is granted concurrently for many tasks because they do not change the resource state. Read write mutexes can be reentrant, global or local. Further, promotion operations may be provided. That's when a [[task]] that has seized the mutex for ''write'' releases it while keeping seized for ''read''. Note that the reverse operation is potentially deadlocking and requires some additional access policy control.
=Deadlock prevention=
There exists a simple technique of deadlock prevention when mutexes are seized in some fixed order. This is discussed in depth in the [[Dining philosophers]] problem.
=Sample implementations / APIs=

View file

@ -0,0 +1,58 @@
;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.
vblankflag equ $02
main:
;if your time-sensitive function has parameters, pre-load them into global memory here.
;The only thing the NMI should have to do is write the data to the hardware registers.
jsr waitframe
LDA #$01 ;there's not enough time for a second vblank to occur between these two calls to waitframe().
STA mutex ;release the mutex. the next NMI will service the function we just unlocked.
jsr waitframe
halt:
jmp halt ;we're done - trap the cpu. NMI will still occur but nothing of interest happens since the mutex is locked.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
nmi: ;every 1/60th of a second the CPU jumps here automatically.
pha
txa
pha
tya
pha ;pushAll
;for simplicity's sake the needs of the hardware are going to be omitted. A real NES game would perform sprite DMA here.
LDA mutex
BEQ exit_nmi
; whatever you wanted to gatekeep behind your mutex goes here.
; typically it would be something like a text box printer, etc.
; Something that needs to update the video RAM and do so ASAP.
LDA #$00
STA mutex ;lock the mutex again.
exit_nmi:
LDA #$01
STA vblankflag ;allow waitframe() to exit
pla
tay
pla
tax
pla ;popAll
rti
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
waitframe:
pha
LDA #0
sta vblankflag
.again:
LDA vblankflag
BEQ again ;this would loop infinitely if it weren't for vblankflag being set during NMI
pla
rts

View file

@ -0,0 +1,2 @@
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]

View file

@ -0,0 +1,6 @@
protected type Mutex is
entry Seize;
procedure Release;
private
Owned : Boolean := False;
end Mutex;

View file

@ -0,0 +1,10 @@
protected body Mutex is
entry Seize when not Owned is
begin
Owned := True;
end Seize;
procedure Release is
begin
Owned := False;
end Release;
end Mutex;

View file

@ -0,0 +1,15 @@
declare
M : Mutex;
begin
M.Seize; -- Wait infinitely for the mutex to be free
... -- Critical code
M.Release; -- Release the mutex
...
select
M.Seize; -- Wait no longer than 0.5s
or delay 0.5;
raise Timed_Out;
end select;
... -- Critical code
M.Release; -- Release the mutex
end;

View file

@ -0,0 +1,13 @@
REM Create mutex:
SYS "CreateMutex", 0, 0, 0 TO hMutex%
REM Wait to acquire mutex:
REPEAT
SYS "WaitForSingleObject", hMutex%, 1 TO res%
UNTIL res% = 0
REM Release mutex:
SYS "ReleaseMutex", hMutex%
REM Free mutex:
SYS "CloseHandle", hMutex%

1
Task/Mutex/C/mutex-1.c Normal file
View file

@ -0,0 +1 @@
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);

1
Task/Mutex/C/mutex-2.c Normal file
View file

@ -0,0 +1 @@
WaitForSingleObject(hMutex, INFINITE);

1
Task/Mutex/C/mutex-3.c Normal file
View file

@ -0,0 +1 @@
ReleaseMutex(hMutex);

1
Task/Mutex/C/mutex-4.c Normal file
View file

@ -0,0 +1 @@
CloseHandle(hMutex);

3
Task/Mutex/C/mutex-5.c Normal file
View file

@ -0,0 +1,3 @@
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2
Task/Mutex/C/mutex-6.c Normal file
View file

@ -0,0 +1,2 @@
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

1
Task/Mutex/C/mutex-7.c Normal file
View file

@ -0,0 +1 @@
int error = pthread_mutex_lock(&mutex);

1
Task/Mutex/C/mutex-8.c Normal file
View file

@ -0,0 +1 @@
int error = pthread_mutex_unlock(&mutex);

1
Task/Mutex/C/mutex-9.c Normal file
View file

@ -0,0 +1 @@
int error = pthread_mutex_trylock(&mutex);

11
Task/Mutex/D/mutex-1.d Normal file
View file

@ -0,0 +1,11 @@
class Synced
{
public:
synchronized int func (int input)
{
num += input;
return num;
}
private:
static num = 0;
}

46
Task/Mutex/D/mutex-2.d Normal file
View file

@ -0,0 +1,46 @@
import tango.core.Thread, tango.io.Stdout, tango.util.log.Trace;
class Synced {
public synchronized int func (int input) {
Trace.formatln("in {} at func enter: {}", input, foo);
// stupid loop to consume some time
int arg;
for (int i = 0; i < 1000*input; ++i) {
for (int j = 0; j < 10_000; ++j) arg += j;
}
foo += input;
Trace.formatln("in {} at func exit: {}", input, foo);
return arg;
}
private static int foo;
}
void main(char[][] args) {
SimpleThread[] ht;
Stdout.print( "Starting application..." ).newline;
for (int i=0; i < 3; i++) {
Stdout.print( "Starting thread for: " )(i).newline;
ht ~= new SimpleThread(i+1);
ht[i].start();
}
// wait for all threads
foreach( s; ht )
s.join();
}
class SimpleThread : Thread
{
private int d_id;
this (int id) {
super (&run);
d_id = id;
}
void run() {
auto tested = new Synced;
Trace.formatln ("in run() {}", d_id);
tested.func(d_id);
}
}

11
Task/Mutex/D/mutex-3.d Normal file
View file

@ -0,0 +1,11 @@
class Synced {
public int func (int input) {
synchronized(Synced.classinfo) {
// ...
foo += input;
// ...
}
return arg;
}
private static int foo;
}

View file

@ -0,0 +1,95 @@
unit main;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms,
System.SyncObjs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
mmo1: TMemo;
btn1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
FMutex: TMutex;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FMutex := TMutex.Create();
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FMutex.Free;
end;
// http://edgarpavao.com/2017/08/07/multithreading-e-processamento-paralelo-no-delphi-ppl/
procedure TForm1.btn1Click(Sender: TObject);
begin
//Thread 1
TThread.CreateAnonymousThread(
procedure
begin
FMutex.Acquire;
try
TThread.Sleep(5000);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
mmo1.Lines.Add('Thread 1');
end);
finally
FMutex.Release;
end;
end).Start;
//Thread 2
TThread.CreateAnonymousThread(
procedure
begin
FMutex.Acquire;
try
TThread.Sleep(1000);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
mmo1.Lines.Add('Thread 2');
end);
finally
FMutex.Release;
end;
end).Start;
//Thread 3
TThread.CreateAnonymousThread(
procedure
begin
FMutex.Acquire;
try
TThread.Sleep(3000);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
mmo1.Lines.Add('Thread 3');
end);
finally
FMutex.Release;
end;
end).Start;
end;
end.

16
Task/Mutex/E/mutex-1.e Normal file
View file

@ -0,0 +1,16 @@
def makeMutex() {
# The mutex is available (released) if available is resolved, otherwise it
# has been seized/locked. The specific value of available is irrelevant.
var available := null
# The interface to the mutex is a function, taking a function (action)
# to be executed.
def mutex(action) {
# By assigning available to our promise here, the mutex remains
# unavailable to the /next/ caller until /this/ action has gotten
# its turn /and/ resolved its returned value.
available := Ref.whenResolved(available, fn _ { action <- () })
}
return mutex
}

39
Task/Mutex/E/mutex-2.e Normal file
View file

@ -0,0 +1,39 @@
Creating the mutex:
? def mutex := makeMutex()
# value: <mutex>
Creating the shared resource:
? var value := 0
# value: 0
Manipulating the shared resource non-atomically so as to show a problem:
? for _ in 0..1 {
> when (def v := (&value) <- get()) -> {
> (&value) <- put(v + 1)
> }
> }
? value
# value: 1
The value has been incremented twice, but non-atomically, and so is 1 rather
than the intended 2.
? value := 0
# value: 0
This time, we use the mutex to protect the action.
? for _ in 0..1 {
> mutex(fn {
> when (def v := (&value) <- get()) -> {
> (&value) <- put(v + 1)
> }
> })
> }
? value
# value: 2

View file

@ -0,0 +1,40 @@
-module( mutex ).
-export( [task/0] ).
task() ->
Mutex = erlang:spawn( fun() -> loop() end ),
[erlang:spawn(fun() -> random:seed( X, 0, 0 ), print(Mutex, X, 3) end) || X <- lists:seq(1, 3)].
loop() ->
receive
{acquire, Pid} ->
Pid ! {access, erlang:self()},
receive
{release, Pid} -> loop()
end
end.
mutex_acquire( Pid ) ->
Pid ! {acquire, erlang:self()},
receive
{access, Pid} -> ok
end.
mutex_release( Pid ) -> Pid ! {release, erlang:self()}.
print( _Mutex, _N, 0 ) -> ok;
print( Mutex, N, M ) ->
timer:sleep( random:uniform(100) ),
mutex_acquire( Mutex ),
io:fwrite( "Print ~p: ", [N] ),
[print_slow(X) || X <- lists:seq(1, 3)],
io:nl(),
mutex_release( Mutex ),
print( Mutex, N, M - 1 ).
print_slow( X ) ->
io:fwrite( " ~p", [X] ),
timer:sleep( 100 ).

View file

@ -0,0 +1,54 @@
' Threading synchronization using Mutexes
' 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.
Const max_hilos = 10
Dim Shared As Any Ptr bloqueo_tty
' Teletipo unfurls some text across the screen at a given location
Sub Teletipo(Byref texto As String, Byval x As Integer, Byval y As Integer)
'
' This MutexLock makes simultaneously running threads wait for each
' other, so only one at a time can continue and print output.
' Otherwise, their Locates would interfere, since there is only one cursor.
'
' It's impossible to predict the order in which threads will arrive here and
' which one will be the first to acquire the lock thus causing the rest to wait.
Mutexlock bloqueo_tty
For i As Integer = 0 To (Len(texto) - 1)
Locate x, y + i : Print Chr(texto[i])
Sleep 25, 1
Next i
' MutexUnlock releases the lock and lets other threads acquire it.
Mutexunlock bloqueo_tty
End Sub
Sub Hilo(Byval datos_usuario As Any Ptr)
Dim As Integer id = Cint(datos_usuario)
Teletipo "Hilo (" & id & ").........", 1 + id, 1
End Sub
' Create a mutex to syncronize the threads
bloqueo_tty = Mutexcreate()
' Create child threads
Dim As Any Ptr sucesos(0 To max_hilos - 1)
For i As Integer = 0 To max_hilos - 1
sucesos(i) = Threadcreate(@Hilo, Cptr(Any Ptr, i))
If sucesos(i) = 0 Then
Print "Error al crear el hilo:"; i
Exit For
End If
Next i
' This is the main thread. Now wait until all child threads have finished.
For i As Integer = 0 To max_hilos - 1
If sucesos(i) <> 0 Then Threadwait(sucesos(i))
Next i
' Clean up when finished
Mutexdestroy(bloqueo_tty)
Sleep

28
Task/Mutex/Go/mutex-1.go Normal file
View file

@ -0,0 +1,28 @@
package main
import (
"fmt"
"sync"
"time"
)
var value int
var m sync.Mutex
var wg sync.WaitGroup
func slowInc() {
m.Lock()
v := value
time.Sleep(1e8)
value = v+1
m.Unlock()
wg.Done()
}
func main() {
wg.Add(2)
go slowInc()
go slowInc()
wg.Wait()
fmt.Println(value)
}

40
Task/Mutex/Go/mutex-2.go Normal file
View file

@ -0,0 +1,40 @@
package main
import (
"fmt"
"time"
)
var value int
func slowInc(ch, done chan bool) {
// channel receive, used here to implement mutex lock.
// it will block until a value is available on the channel
<-ch
// same as above
v := value
time.Sleep(1e8)
value = v + 1
// channel send, equivalent to mutex unlock.
// makes a value available on channel
ch <- true
// channels can be used to signal completion too
done <- true
}
func main() {
ch := make(chan bool, 1) // ch used as a mutex
done := make(chan bool) // another channel used to signal completion
go slowInc(ch, done)
go slowInc(ch, done)
// a freshly created sync.Mutex starts out unlocked, but a freshly created
// channel is empty, which for us represents "locked." sending a value on
// the channel puts the value up for grabs, thus representing "unlocked."
ch <- true
<-done
<-done
fmt.Println(value)
}

View file

@ -0,0 +1,4 @@
takeMVar :: MVar a -> IO a
putMVar :: MVar a -> a -> IO ()
tryTakeMVar :: MVar a -> IO (Maybe a)
tryPutMVar :: MVar a -> a -> IO Bool

View file

@ -0,0 +1,7 @@
x: = mutex() # create and return a mutex handle for sharing between threads needing to synchronize with each other
lock(x) # lock mutex x
trylock(x)) # non-blocking lock, succeeds only if there are no other thread already in the critical region
unlock(x) # unlock mutex x

6
Task/Mutex/J/mutex.j Normal file
View file

@ -0,0 +1,6 @@
name=. 10 T. 0 NB. create an exclusive 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;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
13 T. mutex NB. release lock on mutex

View file

@ -0,0 +1,10 @@
import java.util.concurrent.Semaphore;
public class VolatileClass{
public Semaphore mutex = new Semaphore(1); //also a "fair" boolean may be passed which,
//when true, queues requests for the lock
public void needsToBeSynched(){
//...
}
//delegate methods could be added for acquiring and releasing the mutex
}

View file

@ -0,0 +1,10 @@
public class TestVolitileClass throws Exception{
public static void main(String[] args){
VolatileClass vc = new VolatileClass();
vc.mutex.acquire(); //will wait automatically if another class has the mutex
//can be interrupted similarly to a Thread
//use acquireUninterruptibly() to avoid that
vc.needsToBeSynched();
vc.mutex.release();
}
}

View file

@ -0,0 +1,35 @@
public class Main {
static Object mutex = new Object();
static int i = 0;
public void addAndPrint()
{
System.out.print("" + i + " + 1 = ");
i++;
System.out.println("" + i);
}
public void subAndPrint()
{
System.out.print("" + i + " - 1 = ");
i--;
System.out.println("" + i);
}
public static void main(String[] args){
final Main m = new Main();
new Thread() {
public void run()
{
while (true) { synchronized(m.mutex) { m.addAndPrint(); } }
}
}.start();
new Thread() {
public void run()
{
while (true) { synchronized(m.mutex) { m.subAndPrint(); } }
}
}.start();
}
}

View file

@ -0,0 +1 @@
SpinLock()

View file

@ -0,0 +1 @@
lock(lock)

View file

@ -0,0 +1 @@
unlock(lock)

View file

@ -0,0 +1 @@
trylock(lock)

View file

@ -0,0 +1 @@
islocked(lock)

View file

@ -0,0 +1 @@
ReentrantLock()

View file

@ -0,0 +1,33 @@
:- object(slow_print).
:- threaded.
:- public(start/0).
:- private([slow_print_abc/0, slow_print_123/0]).
:- synchronized([slow_print_abc/0, slow_print_123/0]).
start :-
% launch two threads, running never ending goals
threaded((
repeat_abc,
repeat_123
)).
repeat_abc :-
repeat, slow_print_abc, fail.
repeat_123 :-
repeat, slow_print_123, fail.
slow_print_abc :-
write(a), thread_sleep(0.2),
write(b), thread_sleep(0.2),
write(c), nl.
slow_print_123 :-
write(1), thread_sleep(0.2),
write(2), thread_sleep(0.2),
write(3), nl.
:- end_object.

View file

@ -0,0 +1,55 @@
Form 80, 50
Module CheckIt {
Thread.Plan Concurrent
Class mutex {
mylock as boolean=True
Function Lock {
if not .mylock then exit
.mylock<=False
=True
}
Module Unlock {
.mylock<=True
}
}
Group PhoneBooth {
NowUser$
module UseIt (a$, x){
.NowUser$<=a$
Print a$+" phone home ",Int(x*100);"%"
}
module leave {
.NowUser$<=""
}
}
m=mutex()
Flush
Data "Bob", "John","Tom"
For i=1 to 3 {
Thread {
\\ we use N$, C and Max as stack variables for each thread
\\ all other variables are shared for module
If C=0 Then if not m.lock() then Print N$+" waiting...................................":Refresh 20: Continue
C++
if c=1 then thread this interval 20
PhoneBooth.UseIt N$,C/Max
iF C<Max Then Continue
PhoneBooth.leave
m.Unlock
Thread This Erase
} as K
Read M$
Thread K Execute Static N$=M$, C=0, Max=RANDOM(5,8)
Thread K interval Random(300, 2000)
}
\\ Start we lock Phone Booth for service
Service=m.lock()
Main.Task 50 {
If Service Then if Keypress(32) then m.unlock: Service=false: Continue
If not Service then if Keypress(32) Then if m.lock() then Service=true : Continue
if PhoneBooth.NowUser$<>"" Then {
Print "Phone:";PhoneBooth.NowUser$: Refresh
} Else.if Service then Print "Service Time": Refresh
}
}
CheckIt

View file

@ -0,0 +1,4 @@
import locks
var mutex: Lock
initLock mutex

View file

@ -0,0 +1 @@
acquire mutex

View file

@ -0,0 +1 @@
release mutex

View file

@ -0,0 +1 @@
let success = tryAcquire mutex

View file

@ -0,0 +1,8 @@
let m = Mutex.create() in
Mutex.lock m; (* locks in blocking mode *)
if (Mutex.try_lock m)
then ... (* did the lock *)
else ... (* already locked, do not block *)
Mutex.unlock m;

View file

@ -0,0 +1,6 @@
m := ThreadMutex->New("lock a");
# section locked
critical(m) {
...
}
# section unlocked

View file

@ -0,0 +1,11 @@
NSLock *m = [[NSLock alloc] init];
[m lock]; // locks in blocking mode
if ([m tryLock]) { // acquire a lock -- does not block if not acquired
// lock acquired
} else {
// already locked, does not block
}
[m unlock];

View file

@ -0,0 +1,13 @@
import: parallel
: job(mut)
mut receive drop
"I get the mutex !" .
2000 sleep
"Now I release the mutex" println
1 mut send drop ;
: mymutex
| mut |
Channel new dup send(1) drop ->mut
10 #[ #[ mut job ] & ] times ;

1
Task/Mutex/Oz/mutex-1.oz Normal file
View file

@ -0,0 +1 @@
declare L = {Lock.new}

3
Task/Mutex/Oz/mutex-2.oz Normal file
View file

@ -0,0 +1,3 @@
lock L then
{System.show exclusive}
end

9
Task/Mutex/Oz/mutex-3.oz Normal file
View file

@ -0,0 +1,9 @@
class Test
prop locking
meth test
lock
{Show exclusive}
end
end
end

28
Task/Mutex/Perl/mutex.pl Normal file
View file

@ -0,0 +1,28 @@
use Thread qw'async';
use threads::shared;
my ($lock1, $lock2, $resource1, $resource2) :shared = (0) x 4;
sub use_resource {
{ # curly provides lexical scope, exiting which causes lock to release
lock $lock1;
$resource1 --; # acquire resource
sleep(int rand 3); # artifical delay to pretend real work
$resource1 ++; # release resource
print "In thread ", threads->tid(), ": ";
print "Resource1 is $resource1\n";
}
{
lock $lock2;
$resource2 --;
sleep(int rand 3);
$resource2 ++;
print "In thread ", threads->tid(), ": ";
print "Resource2 is $resource2\n";
}
}
# create 9 threads and clean up each after they are done.
for ( map async{ use_resource }, 1 .. 9) {
$_->join
}

View file

@ -0,0 +1,10 @@
(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: #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: #0000FF;">...</span>
<span style="color: #7060A8;">enter_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;">-- Begin mutually exclusive execution</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">try_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;">-- As enter_cs, but yields false (0) if the lock cannot be obtained instantly</span>
<span style="color: #7060A8;">leave_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;">-- End mutually exclusive execution</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>
<!--

View file

@ -0,0 +1,18 @@
(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: #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: #0000FF;">...</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #000000;">lock_file</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">LOCK_SHARED</span><span style="color: #0000FF;">,{})</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">--while not lock_file(fn,LOCK_EXCLUSIVE,{}) do</span>
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">count</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">></span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- message/abort/retry/...</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #0000FF;">...</span>
<span style="color: #000000;">unlock_file</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><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>
<!--

View file

@ -0,0 +1 @@
mutex_create(Mutex, [alias(my_mutex)]).

View file

@ -0,0 +1 @@
synchronized_goal(G) :- with_mutex(my_mutex, call(G)).

View file

@ -0,0 +1,5 @@
MyMutex=CreateMutex()
Result = TryLockMutex(MyMutex)
LockMutex(MyMutex)
UnlockMutex(MyMutex)
FreeMutex(MyMutex)

View file

@ -0,0 +1,34 @@
Declare ThreadedTask(*MyArgument)
Define Mutex
If OpenConsole()
Define thread1, thread2, thread3
Mutex = CreateMutex()
thread1 = CreateThread(@ThreadedTask(), 1): Delay(5)
thread2 = CreateThread(@ThreadedTask(), 2): Delay(5)
thread3 = CreateThread(@ThreadedTask(), 3)
WaitThread(thread1)
WaitThread(thread2)
WaitThread(thread3)
PrintN(#CRLF$+"Press ENTER to exit"): Input()
FreeMutex(Mutex)
CloseConsole()
EndIf
Procedure ThreadedTask(*MyArgument)
Shared Mutex
Protected a, b
For a = 1 To 3
LockMutex(Mutex)
; Without Lock-/UnLockMutex() here the output from the parallel threads would be all mixed.
; Reading/Writing to shared memory resources are a common use for Mutextes i PureBasic
PrintN("Thread "+Str(*MyArgument)+": Print 3 numbers in a row:")
For b = 1 To 3
Delay(75)
PrintN("Thread "+Str(*MyArgument)+" : "+Str(b))
Next
UnlockMutex(Mutex)
Next
EndProcedure

View file

@ -0,0 +1,30 @@
import threading
from time import sleep
# res: max number of resources. If changed to 1, it functions
# identically to a mutex/lock object
res = 2
sema = threading.Semaphore(res)
class res_thread(threading.Thread):
def run(self):
global res
n = self.getName()
for i in range(1, 4):
# acquire a resource if available and work hard
# for 2 seconds. if all res are occupied, block
# and wait
sema.acquire()
res = res - 1
print n, "+ res count", res
sleep(2)
# after done with resource, return it to pool and flag so
res = res + 1
print n, "- res count", res
sema.release()
# create 4 threads, each acquire resorce and work
for i in range(1, 5):
t = res_thread()
t.start()

View file

@ -0,0 +1,6 @@
(define foo
(let ([sema (make-semaphore 1)])
(lambda (x)
(dynamic-wind (λ() (semaphore-wait sema))
(λ() (... do something ...))
(λ() (semaphore-post sema))))))

View file

@ -0,0 +1,10 @@
(define-syntax-rule (define/atomic (name arg ...) E ...)
(define name
(let ([sema (make-semaphore 1)])
(lambda (arg ...)
(dynamic-wind (λ() (semaphore-wait sema))
(λ() E ...)
(λ() (semaphore-post sema)))))))
;; this does the same as the above now:
(define/atomic (foo x)
(... do something ...))

View file

@ -0,0 +1,3 @@
my $lock = Lock.new;
$lock.protect: { your-ad-here() }

View file

@ -0,0 +1,6 @@
require 'mutex_m'
class SomethingWithMutex
include Mutex_m
...
end

View file

@ -0,0 +1,2 @@
an_object = Object.new
an_object.extend(Mutex_m)

View file

@ -0,0 +1,16 @@
# acquire a lock -- block execution until it becomes free
an_object.mu_lock
# acquire a lock -- return immediately even if not acquired
got_lock = an_object.mu_try_lock
# have a lock?
if an_object.mu_locked? then ...
# release the lock
an_object.mu_unlock
# wrap a lock around a block of code -- block execution until it becomes free
an_object.my_synchronize do
do critical stuff
end

View file

@ -0,0 +1,42 @@
use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
fn main() {
let shared = Arc::new(Mutex::new(String::new()));
let handle1 = {
let value = shared.clone();
thread::spawn(move || {
for _ in 0..20 {
thread::sleep(Duration::from_millis(200));
// The guard is valid until the end of the block
let mut guard = value.lock().unwrap();
guard.push_str("A");
println!("{}", guard);
}
})
};
let handle2 = {
let value = shared.clone();
thread::spawn(move || {
for _ in 0..20 {
thread::sleep(Duration::from_millis(300));
{
// Making the guard scope explicit here
let mut guard = value.lock().unwrap();
guard.push_str("B");
println!("{}", guard);
}
}
})
};
handle1.join().ok();
handle2.join().ok();
shared.lock().ok().map_or((), |it| println!("Done: {}", it));
}

View file

@ -0,0 +1,30 @@
#!/usr/local/bin/shale
thread library // POSIX threads, mutexes and semaphores
time library // We use its sleep function here.
// The threead code which will lock the mutex, print a message,
// then unlock the mutex.
threadCode dup var {
arg dup var swap =
stop lock thread::()
arg "Thread %d has the mutex\n" printf
stop unlock thread::()
} =
stop mutex thread::() // Create the mutex.
stop lock thread::() // Lock it until we've started the threads.
// Now create a few threads that will also try to lock the mutex.
1 threadCode create thread::()
2 threadCode create thread::()
3 threadCode create thread::()
4 threadCode create thread::()
// The threads are all waiting to acquire the mutex.
"Main thread unlocking the mutex now..." println
stop unlock thread::()
// Wait a bit to let the threads do their stuff.
1000 sleep time::() // milliseconds

View file

@ -0,0 +1,13 @@
package require Thread
# How to create a mutex
set m [thread::mutex create]
# This will block if the lock is already held unless the mutex is made recursive
thread::mutex lock $m
# Now locked...
thread::mutex unlock $m
# Unlocked again
# Dispose of the mutex
thread::mutex destroy $m

View file

@ -0,0 +1,11 @@
set rw [thread::rwmutex create]
# Get and drop a reader lock
thread::rwmutex rlock $rw
thread::rwmutex unlock $rw
# Get and drop a writer lock
thread::rwmutex wlock $rw
thread::rwmutex unlock $rw
thread::rwmutex destroy $rw

View file

@ -0,0 +1,14 @@
foreign class Resource {
// obtain a pointer to the resource when available
construct new() {}
// method for using the resource
foreign doSomething()
// signal to the host that the resource is no longer needed
foreign release()
}
var res = Resource.new() // wait for and obtain a lock on the resource
res.doSomething() // use it
res.release() // release the lock

View file

@ -0,0 +1,2 @@
var lock=Atomic.Lock(); lock.acquire(); doSomething(); lock.release();
critical(lock){ doSomething(); }

View file

@ -0,0 +1,4 @@
var lock=Atomic.WriteLock();
lock.acquireForReading(); doSomeReading(); lock.readerRelease();
critical(lock,acquireForReading,readerRelease){ ... }
lock.acquireForWriting(); write(); lock.writerRelease();