Metered concurrency: Difference between revisions

m
(Add Rust implementation)
m (→‎{{header|Wren}}: Minor tidy)
 
(7 intermediate revisions by 6 users not shown)
Line 6:
 
The interface for the counting semaphore is defined in an Ada package specification:
<langsyntaxhighlight lang="ada">package Semaphores is
protected type Counting_Semaphore(Max : Positive) is
entry Acquire;
Line 14:
Lock_Count : Natural := 0;
end Counting_Semaphore;
end Semaphores;</langsyntaxhighlight>
The ''Acquire'' entry has a condition associated with it. A task can only execute the ''Acquire'' entry when ''Lock_Count'' is less than ''Max''. This is the key to making this structure behave as a counting semaphore. This condition, and all the other aspects of ''Counting_Semaphore'' are contained in the package body.
<langsyntaxhighlight lang="ada">package body Semaphores is
 
------------------------
Line 55:
end Counting_Semaphore;
 
end Semaphores;</langsyntaxhighlight>
We now need a set of tasks to properly call an instance of ''Counting_Semaphore''.
<langsyntaxhighlight lang="ada">with Semaphores;
with Ada.Text_Io; use Ada.Text_Io;
 
Line 93:
Crew(I).Start(2.0, I);
end loop;
end Semaphores_Main;</langsyntaxhighlight>
 
=={{header|ALGOL 68}}==
Line 100:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to PAR and SEMA being unimplemented}}
<langsyntaxhighlight lang="algol68">SEMA sem = LEVEL 1;
 
PROC job = (INT n)VOID: (
Line 112:
( DOWN sem ; job(2) ; UP sem ) ,
( DOWN sem ; job(3) ; UP sem )
)</langsyntaxhighlight>
Output:
<pre>
Line 123:
{{works with|BBC BASIC for Windows}}
In BBC BASIC concurrency can only be achieved by timer events (short of running multiple processes).
<langsyntaxhighlight lang="bbcbasic"> INSTALL @lib$+"TIMERLIB"
DIM tID%(6)
Line 183:
PROC_killtimer(tID%(i%))
NEXT
ENDPROC</langsyntaxhighlight>
'''Output:'''
<pre>
Line 205:
=={{header|C}}==
{{works with|POSIX}}
<langsyntaxhighlight lang="c">#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
Line 255:
 
return sem_destroy(&sem);
}</langsyntaxhighlight>
 
=={{header|C sharp}}==
C# has built in semaphore system where acquire is called via Wait(), release with Release() and count with semaphore.CurrentCount.
<langsyntaxhighlight lang="csharp">using System;
using System.Threading;
using System.Threading.Tasks;
Line 287:
}
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
With std::counting_semaphore and std::jthread from c++20's standard library:
 
<syntaxhighlight lang="cpp">#include <chrono>
#include <iostream>
#include <format>
#include <semaphore>
#include <thread>
using namespace std::literals;
 
void Worker(std::counting_semaphore<>& semaphore, int id)
{
semaphore.acquire();
std::cout << std::format("Thread {} has a semaphore & is now working.\n", id); // response message
std::this_thread::sleep_for(2s);
std::cout << std::format("Thread {} done.\n", id);
semaphore.release();
}
int main()
{
const auto numOfThreads = static_cast<int>( std::thread::hardware_concurrency() );
std::counting_semaphore<> semaphore{numOfThreads / 2};
 
std::vector<std::jthread> tasks;
for (int id = 0; id < numOfThreads; ++id)
tasks.emplace_back(Worker, std::ref(semaphore), id);
 
return 0;
}</syntaxhighlight>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">module meteredconcurrency ;
import std.stdio ;
import std.thread ;
Line 338 ⟶ 370:
foreach(inout c ; crew)
c.wait ;
}</langsyntaxhighlight>
===Phobos with tools===
Using the scrapple.tools extension library for Phobos ..
<langsyntaxhighlight lang="d">module metered;
 
import tools.threads, tools.log, tools.time, tools.threadpool;
Line 361 ⟶ 393:
for (int i = 0; i < 10; ++i)
done.acquire;
}</langsyntaxhighlight>
 
=={{header|E}}==
This semaphore slightly differs from the task description; the release operation is not on the semaphore itself but given out with each acquisition, and cannot be invoked too many times.
 
<langsyntaxhighlight lang="e">def makeSemaphore(maximum :(int > 0)) {
var current := 0
def waiters := <elib:vat.makeQueue>()
Line 404 ⟶ 436:
for i in 1..5 {
work(i, 2000, semaphore, timer, println)
}</langsyntaxhighlight>
 
=={{header|EchoLisp}}==
<langsyntaxhighlight lang="scheme">
(require 'tasks) ;; tasks library
 
Line 421 ⟶ 453:
;; run 10 // tasks
(for ([i 10]) (task-run (make-task task i ) (random 500)))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 446 ⟶ 478:
=={{header|Erlang}}==
In this implementation the semaphore is handled as its own process. Taking advantage of erlang's receive queues, which act as a FIFO queue for 'acquire' requests. As workers come online and request the semaphore they will receive it in order. 'receive' has the effect of pausing the process until a message is matched, so there's no idle looping.
<langsyntaxhighlight lang="erlang">
-module(metered).
-compile(export_all).
Line 514 ⟶ 546:
lists:foreach(fun (P) -> receive {done, P} -> ok end end, Pids),
stop(Sem).
</syntaxhighlight>
</lang>
 
=={{header|Euphoria}}==
<langsyntaxhighlight lang="euphoria">sequence sems
sems = {}
constant COUNTER = 1, QUEUE = 2
Line 581 ⟶ 613:
while length(task_list())>1 do
task_yield()
end while</langsyntaxhighlight>
 
Output:
Line 606 ⟶ 638:
 
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">USING: calendar calendar.format concurrency.combinators
concurrency.semaphores formatting kernel sequences threads ;
 
Line 617 ⟶ 649:
] with-semaphore
"task %d released\n" printf
] curry parallel-each</langsyntaxhighlight>
{{out}}
<pre>
Line 641 ⟶ 673:
task 9 released
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">#define MaxThreads 10
 
Dim Shared As Any Ptr ttylock
 
' Teletype unfurls some text across the screen at a given location
Sub teletype(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 ttylock
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 ttylock
End Sub
 
Sub thread(Byval userdata As Any Ptr)
Dim As Integer id = Cint(userdata)
teletype "Thread #" & id & " .........", 1 + id, 1
End Sub
 
' Create a mutex to syncronize the threads
ttylock = Mutexcreate()
 
' Create child threads
Dim As Any Ptr handles(0 To MaxThreads-1)
For i As Integer = 0 To MaxThreads-1
handles(i) = Threadcreate(@thread, Cptr(Any Ptr, i))
If handles(i) = 0 Then Print "Error creating thread:"; i : Exit For
Next i
 
' This is the main thread. Now wait until all child threads have finished.
For i As Integer = 0 To MaxThreads-1
If handles(i) <> 0 Then Threadwait(handles(i))
Next i
 
' Clean up when finished
Mutexdestroy(ttylock)
Sleep</syntaxhighlight>
 
=={{header|Go}}==
Line 651 ⟶ 732:
 
A couple of other concurrency related details used in the example are the log package for serializing output and sync.WaitGroup used as a completion checkpoint. Functions of the fmt package are not synchronized and can produce interleaved output with concurrent writers. The log package does nice synchronization to avoid this.
<langsyntaxhighlight lang="go">package main
 
import (
Line 695 ⟶ 776:
rooms.release()
studied.Done() // signal that student is done
}</langsyntaxhighlight>
Output for this and the other Go programs here shows 10 students studying immediately, about a 2 second pause, 10 more students studying, then another pause of about 2 seconds before returning to the command prompt. In this example the count values may look jumbled. This is a result of the student goroutines running concurrently.
 
===Sync.Cond===
A more traditional approach implementing a counting semaphore object with sync.Cond. It has a constructor and methods for the three operations requested by the task.
<langsyntaxhighlight lang="go">package main
 
import (
Line 760 ⟶ 841:
studyRoom.release()
studied.Done()
}</langsyntaxhighlight>
 
=={{header|Groovy}}==
Solution:
<langsyntaxhighlight lang="groovy">class CountingSemaphore {
private int count = 0
private final int max
Line 781 ⟶ 862:
 
synchronized int getCount() { count }
}</langsyntaxhighlight>
 
Test:
<langsyntaxhighlight lang="groovy">def cs = new CountingSemaphore(4)
(1..12).each { threadID ->
Thread.start {
Line 797 ⟶ 878:
}
}
}</langsyntaxhighlight>
 
Output:
Line 828 ⟶ 909:
The QSem (quantity semaphore) waitQSem and signalQSem functions are the Haskell acquire and release equivalents, and the MVar (synchronizing variable) functions are used to put the workers statuses on the main thread for printing. Note that this code is likely only compatible with GHC due to the use of "threadDelay" from Control.Concurrent.
 
<langsyntaxhighlight Haskelllang="haskell">import Control.Concurrent
( newQSem,
import Control.Monad
signalQSem,
waitQSem,
threadDelay,
forkIO,
newEmptyMVar,
putMVar,
takeMVar,
QSem,
MVar )
import Control.Monad ( replicateM_ )
 
worker :: QSem -> MVar String -> Int -> IO ()
worker q m n = do
waitQSem q
putMVar m $ "Worker " ++<> show n ++<> " has acquired the lock."
threadDelay 2000000 -- microseconds!
signalQSem q
putMVar m $ "Worker " ++<> show n ++<> " has released the lock."
 
main :: IO ()
main = do
q <- newQSem 3
m <- newEmptyMVar
let workers = 5
prints = 2 * workers
mapM_ (forkIO . worker q m) [1 .. workers]
replicateM_ prints $ takeMVar m >>= printputStrLn</langsyntaxhighlight>
 
==Icon and {{header|Unicon}}==
 
Icon doesn't support concurrency. A Unicon solution is:
<langsyntaxhighlight lang="unicon">procedure main(A)
n := integer(A[1] | 3) # Max. number of active tasks
m := integer(A[2] | 2) # Number of visits by each task
Line 867 ⟶ 958:
 
every wait(!threads)
end</langsyntaxhighlight>
 
Sample run:
Line 904 ⟶ 995:
->
</pre>
 
=={{header|J}}==
 
Here's an approach which uses the new (j904, currently in beta) threading primitives:
 
<syntaxhighlight lang="j">metcon=: {{
sleep=: 6!:3
task=: {{
11 T. lock NB. wait
sleep 2
echo 'Task ',y,&":' has the semaphore'
13 T. lock NB. release
}}
lock=: 10 T. 0
0&T.@'' each i.0>.4-1 T.'' NB. ensure at least four threads
> task t.''"0 i.10 NB. dispatch and wait for 10 tasks
14 T. lock NB. discard lock
}}</syntaxhighlight>
 
An example run might look like this:
 
<syntaxhighlight lang="j"> metcon''
Task 0 has the semaphore
Task 1 has the semaphore
Task 2 has the semaphore
Task 3 has the semaphore
Task 4 has the semaphore
Task 9 has the semaphore
Task 5 has the semaphore
Task 7 has the semaphore
Task 8 has the semaphore
Task 6 has the semaphore</syntaxhighlight>
 
An alternative implementation, while (barely) sufficient for this task's requirements, is for demonstration purposes only, and is not meant for serious work:
 
<syntaxhighlight lang="j">scheduledumb=: {{
id=:'dumb',":x:6!:9''
wd 'pc ',id
(t)=: u {{u 0{::n[y[erase 1{::n}} (y;t=. id,'_timer')
wd 'ptimer ',":?100
}}
 
sleep=: 6!:3 NB. seconds
timestamp=: 6!:1 NB. seconds
 
acquire=: {{
imprison y
while. 1<count y do.
release y
sleep 0.1
imprison y
end.
}}
 
release=: {{ counter=: (<:y{counter) y} counter }}
imprison=: {{ counter=: (>:y{counter) y} counter }}
count=: {{ y { counter }}
 
counter=: 0 0
 
demo=: {{
acquire 0
echo 'unit ',y,&":' acquired semaphore, t=',":timestamp''
sleep 2
release 0
}}</syntaxhighlight>
 
Task example:
 
<syntaxhighlight lang="j"> demo scheduledumb"0 i.5
unit 1 acquired semaphore, t=54683.6
unit 0 acquired semaphore, t=54685.6
unit 4 acquired semaphore, t=54687.7
unit 2 acquired semaphore, t=54689.7
unit 3 acquired semaphore, t=54691.7</syntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">public class CountingSemaphore{
private int lockCount = 0;
private int maxCount;
Line 964 ⟶ 1,130:
 
}
}</langsyntaxhighlight>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">
function acquire(num, sem)
sleep(rand())
Line 989 ⟶ 1,155:
 
runsem(4)
</langsyntaxhighlight>{{output}}<pre>
Sleeping and running 4 tasks.
Task 4 waiting for semaphore
Line 1,003 ⟶ 1,169:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.51
 
import java.util.concurrent.Semaphore
Line 1,022 ⟶ 1,188:
}
}
}</langsyntaxhighlight>
 
Sample output:
Line 1,048 ⟶ 1,214:
=={{header|Logtalk}}==
Using Logtalk's multi-threading notifications, which use a per-object FIFO message queue, thus avoiding the need of idle-loops. Works when using SWI-Prolog, XSB, or YAP as the backend compiler.
<langsyntaxhighlight lang="logtalk">
:- object(metered_concurrency).
 
Line 1,106 ⟶ 1,272:
 
:- end_object.
</syntaxhighlight>
</lang>
Output:
<langsyntaxhighlight lang="text">
| ?- metered_concurrency::run.
Worker 1 acquired semaphore
Line 1,125 ⟶ 1,291:
Worker 4 releasing semaphore
yes
</syntaxhighlight>
</lang>
 
=={{header|Nim}}==
Line 1,132 ⟶ 1,298:
 
This program must be compiled with option <code>--threads:on</code>.
<langsyntaxhighlight Nimlang="nim">import os, posix, strformat
 
type SemaphoreError = object of CatchableError
Line 1,183 ⟶ 1,349:
for n in 0..9: createThread(threads[n], task, n)
threads.joinThreads()
sem.close()</langsyntaxhighlight>
 
{{out}}
Line 1,246 ⟶ 1,412:
Using Nim standard mechanisms provided by module “locks”. As for the previous program, it must be compiled with option <code>--threads:on</code>.
 
<langsyntaxhighlight Nimlang="nim">import locks, os, strformat
 
type Semaphore = object
Line 1,308 ⟶ 1,474:
for n in 0..9: createThread(threads[n], task, n)
threads.joinThreads()
sem.close()</langsyntaxhighlight>
 
{{out}}
Line 1,376 ⟶ 1,542:
If the channel is empty a task will wait until it is no more empty.
 
<langsyntaxhighlight lang="oforth">import: parallel
 
Object Class new: Semaphore(ch)
Line 1,385 ⟶ 1,551:
 
Semaphore method: acquire @ch receive drop ;
Semaphore method: release 1 @ch send drop ;</langsyntaxhighlight>
 
Usage :
 
<langsyntaxhighlight lang="oforth">: mytask(s)
while( true ) [
s acquire "Semaphore acquired" .cr
Line 1,399 ⟶ 1,565:
| s i |
Semaphore new(n) ->s
10 loop: i [ #[ s mytask ] & ] ;</langsyntaxhighlight>
 
=={{header|Oz}}==
Counting semaphores can be implemented in terms of mutexes (called "locks" in Oz) and dataflow variables (used as condition variables here). The mutex protects both the counter and the mutable reference to the dataflow variable.
<langsyntaxhighlight lang="oz">declare
fun {NewSemaphore N}
sem(max:N count:{NewCell 0} 'lock':{NewLock} sync:{NewCell _})
Line 1,462 ⟶ 1,628:
for I in 1..10 do
{StartWorker I}
end</langsyntaxhighlight>
 
=={{header|Perl}}==
Line 1,469 ⟶ 1,635:
=={{header|Phix}}==
{{trans|Euphoria}}
<!--<syntaxhighlight lang="phix">(notonline)-->
Requires 0.7.6 or later
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (tasks)</span>
<lang Phix>sequence sems = {}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">sems</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
constant COUNTER = 1, QUEUE = 2
<span style="color: #008080;">constant</span> <span style="color: #000000;">COUNTER</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">QUEUE</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
 
function semaphore(integer n)
<span style="color: #008080;">function</span> <span style="color: #000000;">semaphore</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
if n>0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
sems = append(sems,{n,{}})
<span style="color: #000000;">sems</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sems</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,{}})</span>
return length(sems)
<span style="color: #008080;">return</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sems</span><span style="color: #0000FF;">)</span>
else
<span style="color: #008080;">else</span>
return 0
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
procedure acquire(integer id)
<span style="color: #008080;">procedure</span> <span style="color: #000000;">acquire</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">id</span><span style="color: #0000FF;">)</span>
if sems[id][COUNTER]=0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">COUNTER</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
task_suspend(task_self())
<span style="color: #000000;">task_suspend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">task_self</span><span style="color: #0000FF;">())</span>
sems[id][QUEUE] &= task_self()
<span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">QUEUE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">task_self</span><span style="color: #0000FF;">()</span>
task_yield()
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
sems[id][COUNTER] -= 1
<span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">COUNTER</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
procedure release(integer id)
<span style="color: #008080;">procedure</span> <span style="color: #000000;">release</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">id</span><span style="color: #0000FF;">)</span>
sems[id][COUNTER] += 1
<span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">COUNTER</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
if length(sems[id][QUEUE])>0 then
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">QUEUE</span><span style="color: #0000FF;">])></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
task_schedule(sems[id][QUEUE][1],1)
<span style="color: #000000;">task_schedule</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">QUEUE</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
sems[id][QUEUE] = sems[id][QUEUE][2..$]
<span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">QUEUE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">QUEUE</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
function count(integer id)
<span style="color: #008080;">function</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">id</span><span style="color: #0000FF;">)</span>
return sems[id][COUNTER]
<span style="color: #008080;">return</span> <span style="color: #000000;">sems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">id</span><span style="color: #0000FF;">][</span><span style="color: #000000;">COUNTER</span><span style="color: #0000FF;">]</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
procedure delay(atom delaytime)
<span style="color: #008080;">procedure</span> <span style="color: #000000;">delay</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">delaytime</span><span style="color: #0000FF;">)</span>
atom t = time()
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
while time()-t<delaytime do
<span style="color: #008080;">while</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t</span><span style="color: #0000FF;"><</span><span style="color: #000000;">delaytime</span> <span style="color: #008080;">do</span>
task_yield()
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
integer sem = semaphore(4)
<span style="color: #004080;">integer</span> <span style="color: #000000;">sem</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">semaphore</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
 
procedure worker()
<span style="color: #008080;">procedure</span> <span style="color: #000000;">worker</span><span style="color: #0000FF;">()</span>
acquire(sem)
<span style="color: #000000;">acquire</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sem</span><span style="color: #0000FF;">)</span>
printf(1,"- Task %d acquired semaphore.\n",task_self())
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"- Task %d acquired semaphore.\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">task_self</span><span style="color: #0000FF;">())</span>
delay(2)
<span style="color: #000000;">delay</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
release(sem)
<span style="color: #000000;">release</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sem</span><span style="color: #0000FF;">)</span>
printf(1,"+ Task %d released semaphore.\n",task_self())
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+ Task %d released semaphore.\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">task_self</span><span style="color: #0000FF;">())</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
for i=1 to 10 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
integer task = task_create(routine_id("worker"),{})
<span style="color: #004080;">integer</span> <span style="color: #000000;">task</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">task_create</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"worker"</span><span style="color: #0000FF;">),{})</span>
task_schedule(task,1)
<span style="color: #000000;">task_schedule</span><span style="color: #0000FF;">(</span><span style="color: #000000;">task</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
task_yield()
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
 
integer sc = 0
<span style="color: #004080;">integer</span> <span style="color: #000000;">sc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
atom t0 = time()+1
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
while length(task_list())>1 do
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">task_list</span><span style="color: #0000FF;">())></span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
task_yield()
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
integer scnew = count(sem)
<span style="color: #004080;">integer</span> <span style="color: #000000;">scnew</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sem</span><span style="color: #0000FF;">)</span>
if scnew!=sc
<span style="color: #008080;">if</span> <span style="color: #000000;">scnew</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">sc</span>
or time()>t0 then
<span style="color: #008080;">or</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()></span><span style="color: #000000;">t0</span> <span style="color: #008080;">then</span>
sc = scnew
<span style="color: #000000;">sc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">scnew</span>
printf(1,"Semaphore count now %d\n",{sc})
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Semaphore count now %d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">sc</span><span style="color: #0000FF;">})</span>
t0 = time()+2
<span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">2</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
?"done"</lang>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,569 ⟶ 1,738:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(let Sem (tmp "sem")
(for U 4 # Create 4 concurrent units
(unless (fork)
Line 1,576 ⟶ 1,745:
(wait 2000)
(prinl "Unit " U " releasing the semaphore") )
(bye) ) ) )</langsyntaxhighlight>
 
=={{header|PureBasic}}==
Line 1,582 ⟶ 1,751:
After a thread has completed it releases the Semaphore and a new thread will
be able to start.
<langsyntaxhighlight PureBasiclang="purebasic">#Threads=10
#Parallels=3
Global Semaphore=CreateSemaphore(#Parallels)
Line 1,605 ⟶ 1,774:
WaitThread(i)
EndIf
Next</langsyntaxhighlight>
Sample output
<pre>Thread #0 active.
Line 1,623 ⟶ 1,792:
Python threading module includes a semaphore implementation. This code show how to use it.
 
<langsyntaxhighlight lang="python">import time
import threading
 
Line 1,659 ⟶ 1,828:
running = 0
for t in workers:
t.join()</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 1,677 ⟶ 1,846:
(printf "Job #~a done\n" i)
(semaphore-post sema)))))
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
Uses a buffered channel to hand out a limited number of tickets.
<syntaxhighlight lang="raku" perl6line>class Semaphore {
has $.tickets = Channel.new;
method new ($max) {
Line 1,704 ⟶ 1,873:
}
await @units;
}</langsyntaxhighlight>
{{out}}
<pre>unit 0 acquired
Line 1,720 ⟶ 1,889:
Counting semaphores are built in:
 
<langsyntaxhighlight lang="raven"># four workers may be concurrent
4 semaphore as sem
 
Line 1,736 ⟶ 1,905:
group
10 each drop worker
list as workers</langsyntaxhighlight>
 
Thread joining is automatic by default.
Line 1,743 ⟶ 1,912:
 
This one uses SizedQueue class from the standard library since it blocks when the size limit is reached. An alternative approach would be having a mutex and a counter and blocking explicitly.
<langsyntaxhighlight lang="ruby">
require 'thread'
 
Line 1,789 ⟶ 1,958:
threads.each(&:join)
 
</syntaxhighlight>
</lang>
=={{header|Rust}}==
<langsyntaxhighlight lang="rust">
//! Rust has a perfectly good Semaphore type already. It lacks count(), though, so we can't use it
//! directly.
Line 1,906 ⟶ 2,075:
}
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,932 ⟶ 2,101:
 
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">class CountingSemaphore(var maxCount: Int) {
private var lockCount = 0
 
Line 1,961 ⟶ 2,130:
}
}
}</langsyntaxhighlight>
 
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
Uses the Thread package, which is expected to form part of the overall Tcl 8.6 release.
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
package require Thread
 
Line 2,031 ⟶ 2,200:
foreach t $threads {
thread::release -wait $t
}</langsyntaxhighlight>
 
=={{header|UnixPipes}}==
The number of concurrent jobs can be set by issuing that many echo '1''s at the begining to sem.
 
<langsyntaxhighlight lang="bash">rm -f sem ; mkfifo sem
 
acquire() {
Line 2,054 ⟶ 2,223:
( acquire < sem ; job 3 ; release > sem ) &
 
echo 'Initialize Jobs' >&2 ; echo '1' > sem</langsyntaxhighlight>
 
=={{header|Visual Basic .NET}}==
Line 2,060 ⟶ 2,229:
This code shows using a local semaphore. Semaphores can also be named, in which case they will be shared system wide.
 
<langsyntaxhighlight lang="vbnet">Dim sem As New Semaphore(5, 5) 'Indicates that up to 5 resources can be aquired
sem.WaitOne() 'Blocks until a resouce can be aquired
Dim oldCount = sem.Release() 'Returns a resource to the pool
'oldCount has the Semaphore's count before Release was called</langsyntaxhighlight>
 
=={{header|Wren}}==
{{libheader|Wren-queue}}
In Wren, only one fiber can be run at a time but can yield control to another fiber and be resumed later. Also other tasks can be scheduled to run when a fiber is suspended by its sleep method. The following script (with 6 tasks) therefore takes just over 4 seconds to run rather than 12.
<langsyntaxhighlight ecmascriptlang="wren">import "scheduler" for Scheduler
import "timer" for Timer
import "./queue" for Queue
 
class CountingSemaphore {
Line 2,131 ⟶ 2,300:
// call the first one
tasks[0].call(1)
System.print("\nAll %(numTasks) tasks completed!")</langsyntaxhighlight>
 
{{out}}
Line 2,166 ⟶ 2,335:
=={{header|zkl}}==
Semaphores are built in.
<langsyntaxhighlight lang="zkl">fcn job(name,sem){
name.println(" wait"); sem.acquire();
name.println(" go"); Atomic.sleep(2);
Line 2,173 ⟶ 2,342:
// start 3 threads using the same semphore
s:=Thread.Semaphore(1);
job.launch("1",s); job.launch("2",s); job.launch("3",s);</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits