Metered concurrency: Difference between revisions

m
(→‎Buffered channel: bug fix. previous version worked with existing compiler but was technically invalid.)
m (→‎{{header|Wren}}: Minor tidy)
 
(41 intermediate revisions by 26 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 118:
Job 1 acquired Semaphore ... Job 1 releasing Semaphore
Job 2 acquired Semaphore ... Job 2 releasing Semaphore
</pre>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
In BBC BASIC concurrency can only be achieved by timer events (short of running multiple processes).
<syntaxhighlight lang="bbcbasic"> INSTALL @lib$+"TIMERLIB"
DIM tID%(6)
REM Two workers may be concurrent
DIM Semaphore%(2)
tID%(6) = FN_ontimer(11, PROCtimer6, 1)
tID%(5) = FN_ontimer(10, PROCtimer5, 1)
tID%(4) = FN_ontimer(11, PROCtimer4, 1)
tID%(3) = FN_ontimer(10, PROCtimer3, 1)
tID%(2) = FN_ontimer(11, PROCtimer2, 1)
tID%(1) = FN_ontimer(10, PROCtimer1, 1)
ON CLOSE PROCcleanup : QUIT
ON ERROR PRINT REPORT$ : PROCcleanup : END
sc% = 0
REPEAT
oldsc% = sc%
sc% = -SUM(Semaphore%())
IF sc%<>oldsc% PRINT "Semaphore count now ";sc%
WAIT 0
UNTIL FALSE
DEF PROCtimer1 : PROCtask(1) : ENDPROC
DEF PROCtimer2 : PROCtask(2) : ENDPROC
DEF PROCtimer3 : PROCtask(3) : ENDPROC
DEF PROCtimer4 : PROCtask(4) : ENDPROC
DEF PROCtimer5 : PROCtask(5) : ENDPROC
DEF PROCtimer6 : PROCtask(6) : ENDPROC
DEF PROCtask(n%)
LOCAL i%, temp%
PRIVATE delay%(), sem%()
DIM delay%(6), sem%(6)
IF delay%(n%) THEN
delay%(n%) -= 1
IF delay%(n%) = 0 THEN
SWAP Semaphore%(sem%(n%)),temp%
delay%(n%) = -1
PRINT "Task " ; n% " released semaphore"
ENDIF
ENDPROC
ENDIF
FOR i% = 1 TO DIM(Semaphore%(),1)
temp% = TRUE
SWAP Semaphore%(i%),temp%
IF NOT temp% EXIT FOR
NEXT
IF temp% THEN ENDPROC : REM Waiting to acquire semaphore
sem%(n%) = i%
delay%(n%) = 200
PRINT "Task "; n% " acquired semaphore"
ENDPROC
DEF PROCcleanup
LOCAL i%
FOR i% = 1 TO 6
PROC_killtimer(tID%(i%))
NEXT
ENDPROC</syntaxhighlight>
'''Output:'''
<pre>
Task 1 acquired semaphore
Task 2 acquired semaphore
Semaphore count now 2
Task 1 released semaphore
Task 3 acquired semaphore
Task 2 released semaphore
Task 4 acquired semaphore
Task 3 released semaphore
Task 5 acquired semaphore
Task 4 released semaphore
Task 6 acquired semaphore
Task 5 released semaphore
Semaphore count now 1
Task 6 released semaphore
Semaphore count now 0
</pre>
 
=={{header|C}}==
{{works with|POSIX}}
<langsyntaxhighlight lang="c">#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
Line 172 ⟶ 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 204 ⟶ 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 255 ⟶ 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 278 ⟶ 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 320 ⟶ 436:
for i in 1..5 {
work(i, 2000, semaphore, timer, println)
}</langsyntaxhighlight>
 
=={{header|EchoLisp}}==
<syntaxhighlight lang="scheme">
(require 'tasks) ;; tasks library
 
(define (task id)
(wait S) ;; acquire, p-op
(printf "task %d acquires semaphore @ %a" id (date->time-string (current-date)))
(sleep 2000)
(signal S) ;; release, v-op
id)
(define S (make-semaphore 4)) ;; semaphore with init count 4
 
;; run 10 // tasks
(for ([i 10]) (task-run (make-task task i ) (random 500)))
</syntaxhighlight>
{{out}}
<pre>
task 1 acquires semaphore @ 19:23:03
task 6 acquires semaphore @ 19:23:03
task 4 acquires semaphore @ 19:23:03
task 7 acquires semaphore @ 19:23:03
task 8 acquires semaphore @ 19:23:05
task 9 acquires semaphore @ 19:23:05
task 0 acquires semaphore @ 19:23:05
task 3 acquires semaphore @ 19:23:05
task 2 acquires semaphore @ 19:23:07
task 1 acquires semaphore @ 19:23:07
task 6 acquires semaphore @ 19:23:07
task 5 acquires semaphore @ 19:23:08
task 7 acquires semaphore @ 19:23:09
task 4 acquires semaphore @ 19:23:09
task 9 acquires semaphore @ 19:23:10
task 8 acquires semaphore @ 19:23:10
task 0 acquires semaphore @ 19:23:11
;; etc.
</pre>
 
=={{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.
<syntaxhighlight lang="erlang">
-module(metered).
-compile(export_all).
 
create_semaphore(N) ->
spawn(?MODULE, sem_loop, [N,N]).
 
sem_loop(0,Max) ->
io:format("Resources exhausted~n"),
receive
{release, PID} ->
PID ! released,
sem_loop(1,Max);
{stop, _PID} ->
ok
end;
sem_loop(N,N) ->
receive
{acquire, PID} ->
PID ! acquired,
sem_loop(N-1,N);
{stop, _PID} ->
ok
end;
sem_loop(N,Max) ->
receive
{release, PID} ->
PID ! released,
sem_loop(N+1,Max);
{acquire, PID} ->
PID ! acquired,
sem_loop(N-1,Max);
{stop, _PID} ->
ok
end.
 
release(Sem) ->
Sem ! {release, self()},
receive
released ->
ok
end.
acquire(Sem) ->
Sem ! {acquire, self()},
receive
acquired ->
ok
end.
 
start() -> create_semaphore(10).
 
stop(Sem) -> Sem ! {stop, self()}.
 
worker(P,N,Sem) ->
acquire(Sem),
io:format("Worker ~b has the acquired semaphore~n",[N]),
timer:sleep(500 * random:uniform(4)),
release(Sem),
io:format("Worker ~b has released the semaphore~n",[N]),
P ! {done, self()}.
 
test() ->
Sem = start(),
Pids = lists:map(fun (N) ->
spawn(?MODULE, worker, [self(),N,Sem])
end, lists:seq(1,20)),
lists:foreach(fun (P) -> receive {done, P} -> ok end end, Pids),
stop(Sem).
</syntaxhighlight>
 
=={{header|Euphoria}}==
<langsyntaxhighlight lang="euphoria">sequence sems
sems = {}
constant COUNTER = 1, QUEUE = 2
Line 386 ⟶ 613:
while length(task_list())>1 do
task_yield()
end while</langsyntaxhighlight>
 
Output:
Line 409 ⟶ 636:
+ Task 10 released semaphore.
+ Task 9 released semaphore.</pre>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: calendar calendar.format concurrency.combinators
concurrency.semaphores formatting kernel sequences threads ;
 
10 <iota> 2 <semaphore>
[
[
dup now timestamp>hms
"task %d acquired semaphore at %s\n" printf
2 seconds sleep
] with-semaphore
"task %d released\n" printf
] curry parallel-each</syntaxhighlight>
{{out}}
<pre>
task 0 acquired semaphore at 01:43:24
task 1 acquired semaphore at 01:43:24
task 0 released
task 2 acquired semaphore at 01:43:26
task 1 released
task 3 acquired semaphore at 01:43:26
task 2 released
task 4 acquired semaphore at 01:43:28
task 3 released
task 5 acquired semaphore at 01:43:28
task 4 released
task 6 acquired semaphore at 01:43:30
task 5 released
task 7 acquired semaphore at 01:43:30
task 6 released
task 8 acquired semaphore at 01:43:32
task 7 released
task 9 acquired semaphore at 01:43:32
task 8 released
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}}==
===Buffered channel===
Recommended solution for simplicity. Acquire operation is channel send, release is channel receive, and count is provided with len(channel).cap and Also WaitGroup used as a completion checkpointlen.
 
<lang go>package main
To demonstrate, this example implements the [https://en.wikipedia.org/wiki/Semaphore_(programming)#Library_analogy Library analogy] from Wikipedia with 10 study rooms and 20 students.
 
The channel type shown here is <code>struct{}</code>. <code>struct{}</code> is nice because it has zero size and zero content, although the syntax is slightly akward. Other popular choices for no-content tokens are ints and bools. They read a little nicer but waste a few bytes and could potentially mislead someone to think the values had some meaning.
 
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.
<syntaxhighlight lang="go">package main
 
import (
"log"
Line 421 ⟶ 740:
"time"
)
 
// counting semaphore implemented with a buffered channel
type sem chan struct{}
 
func (s sem) acquire() { s <- struct{}{} }
func (s sem) release() { <-s }
func (s sem) count() int { return cap(s) - len(s) }
 
// log package serializes output
var fmt = log.New(os.Stdout, "", 0)
 
// library analogy per WP article
const nRooms = 10
const nStudents = 20
 
func main() {
rooms := make(sem, nRooms)
// buffered channel used as a counting semaphore
rooms := make(chan int, nRooms)
for i := 0; i < nRooms; i++ {
rooms <- 1
}
// WaitGroup used to wait for all students to have studied
// before terminating program
Line 445 ⟶ 767:
studied.Wait()
}
 
func student(rooms chan intsem, studied *sync.WaitGroup) {
<-rooms // .acquire operation()
// report per task descrption. also exercise count operation
fmt.Printf("Room entered. Count is %d. Studying...\n",
len(rooms.count()) // len function provides count operation
time.Sleep(2 * time.Second) // sleep per task description
rooms <- 1 // .release operation()
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 465 ⟶ 787:
"os"
"sync"
"sync/atomic"
"time"
)
Line 472 ⟶ 793:
 
type countSem struct {
c int32int
cond *sync.Cond
}
 
func newCount(n int) *countSem {
return &countSem{int32(n), sync.NewCond(new(Cond{L: &sync.Mutex)){}}}
}
 
func (cs *countSem) count() int {
cs.L.Lock()
return int(atomic.LoadInt32(&cs.c))
c := cs.int
cs.L.Unlock()
return c
}
 
func (cs *countSem) acquire() {
cs.L.Lock()
if atomic.AddInt32(&cs.c, -1) < 0 {
atomic.AddInt32(&cs.c, 1)int--
for cs.int < 0 cs.cond.L.Lock(){
for atomiccs.AddInt32Wait(&cs.c, -1) < 0 {
atomic.AddInt32(&cs.c, 1)
cs.cond.Wait()
}
cs.cond.L.Unlock()
}
cs.L.Unlock()
}
 
func (cs *countSem) release() {
atomic.AddInt32(&cs.c, 1L.Lock()
cs.cond.Signal()int++
cs.L.Unlock()
cs.Broadcast()
}
 
Line 518 ⟶ 841:
studyRoom.release()
studied.Done()
}</langsyntaxhighlight>
===Monitor===
Monitor-style solution implements counting semaphore as a monitor goroutine encapsulating the count. It implements semaphore operations with separate Go channels.
<lang go>package main
 
=={{header|Groovy}}==
import (
Solution:
"log"
<syntaxhighlight lang="groovy">class CountingSemaphore {
"os"
private int count = 0
"sync"
private final int max
"time"
)
 
CountingSemaphore(int max) { this.max = max }
var fmt = log.New(os.Stdout, "", 0)
 
synchronized int acquire() {
func main() {
while (count >= max) { wait() }
// three operations per task description
acquire := make(chan int) ++count
}
release := make(chan int)
count := make(chan chan int)
 
synchronized int release() {
// library analogy per WP article
go librarian if (acquire,count) release,{ count,--; 10notifyAll() }
nStudents := 20 count
var studied sync.WaitGroup
studied.Add(nStudents)
for i := 0; i < nStudents; i++ {
go student(acquire, release, count, &studied)
}
// wait until all students have studied before terminating program
studied.Wait()
}
 
func librarian(a, r chan synchronized int, cgetCount() chan chan int,{ count int) {}
}</syntaxhighlight>
p := a // acquire operation is served or not depending on count
 
for {
Test:
select {
<syntaxhighlight lang="groovy">def cs = new CountingSemaphore(4)
case <-p: // acquire/p/wait operation
(1..12).each { threadID ->
count--
if count == 0Thread.start {
def id = "Thread #${(threadID as p = nilString).padLeft(2,'0')}"
try }{
case <-r: def sCount = // release/v operationcs.acquire()
println("${id} has acquired Semaphore at count++ = ${sCount}")
p = asleep(2000)
case} ccfinally := <-c: // count operation{
ccprintln("${id} <-is releasing Semaphore at count = ${cs.count}")
cs.release()
}
}
}</syntaxhighlight>
}
 
Output:
func student(a, r chan int, c chan chan int, studied *sync.WaitGroup) {
<pre style="height:30ex;overflow:scroll;">Thread #03 has acquired Semaphore at count = 4
cc := make(chan int)
Thread #07 has acquired Semaphore at count = 2
a <- 0 // acquire
Thread #02 has acquired Semaphore at count = 1
c <- cc // request count
Thread #09 has acquired Semaphore at count = 3
fmt.Printf("Room entered. Count is %d. Studying...\n", <-cc)
Thread #03 is releasing Semaphore at count = 4
time.Sleep(2 * time.Second) // sleep per task description
Thread #02 is releasing Semaphore at count = 4
r <- 0 // release
Thread #09 is releasing Semaphore at count = 4
studied.Done() // signal done
Thread #07 is releasing Semaphore at count = 4
}</lang>
Thread #12 has acquired Semaphore at count = 4
Thread #05 has acquired Semaphore at count = 3
Thread #06 has acquired Semaphore at count = 4
Thread #08 has acquired Semaphore at count = 2
Thread #12 is releasing Semaphore at count = 4
Thread #06 is releasing Semaphore at count = 4
Thread #05 is releasing Semaphore at count = 4
Thread #10 has acquired Semaphore at count = 4
Thread #11 has acquired Semaphore at count = 4
Thread #08 is releasing Semaphore at count = 3
Thread #01 has acquired Semaphore at count = 4
Thread #04 has acquired Semaphore at count = 4
Thread #11 is releasing Semaphore at count = 4
Thread #10 is releasing Semaphore at count = 4
Thread #04 is releasing Semaphore at count = 2
Thread #01 is releasing Semaphore at count = 2</pre>
 
=={{header|Haskell}}==
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:
<syntaxhighlight 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
k := integer(A[3] | 5) # Number of tasks
sem := [: |mutex([])\n :]
every put(threads := [], (i := 1 to k, thread
every 1 to m do {
write("unit ",i," ready")
until flag := trylock(!sem)
write("unit ",i," running")
delay(2000)
write("unit ",i," done")
unlock(flag)
}))
 
every wait(!threads)
end</syntaxhighlight>
 
Sample run:
<pre>
->mc
unit 2 ready
unit 2 running
unit 1 ready
unit 1 running
unit 3 ready
unit 3 running
unit 4 ready
unit 5 ready
unit 2 done
unit 2 ready
unit 5 running
unit 1 done
unit 2 running
unit 1 ready
unit 3 done
unit 3 ready
unit 4 running
unit 5 done
unit 5 ready
unit 1 running
unit 2 done
unit 5 running
unit 4 done
unit 3 running
unit 4 ready
unit 1 done
unit 4 running
unit 5 done
unit 3 done
unit 4 done
->
</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 660 ⟶ 1,130:
 
}
}</langsyntaxhighlight>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">
function acquire(num, sem)
sleep(rand())
println("Task $num waiting for semaphore")
lock(sem)
println("Task $num has acquired semaphore")
sleep(rand())
unlock(sem)
end
 
 
function runsem(numtasks)
println("Sleeping and running $numtasks tasks.")
sem = Base.Threads.RecursiveSpinLock()
@sync(
for i in 1:numtasks
@async acquire(i, sem)
end)
println("Done.")
end
 
runsem(4)
</syntaxhighlight>{{output}}<pre>
Sleeping and running 4 tasks.
Task 4 waiting for semaphore
Task 4 has acquired semaphore
Task 1 waiting for semaphore
Task 1 has acquired semaphore
Task 2 waiting for semaphore
Task 2 has acquired semaphore
Task 3 waiting for semaphore
Task 3 has acquired semaphore
Done.
</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.51
 
import java.util.concurrent.Semaphore
import kotlin.concurrent.thread
 
fun main(args: Array<String>) {
val numPermits = 4
val numThreads = 9
val semaphore = Semaphore(numPermits)
for (i in 1..numThreads) {
thread {
val name = "Unit #$i"
semaphore.acquire()
println("$name has acquired the semaphore")
Thread.sleep(2000)
semaphore.release()
println("$name has released the semaphore")
}
}
}</syntaxhighlight>
 
Sample output:
<pre>
Unit #1 has acquired the semaphore
Unit #2 has acquired the semaphore
Unit #3 has acquired the semaphore
Unit #4 has acquired the semaphore
Unit #1 has released the semaphore
Unit #5 has acquired the semaphore
Unit #2 has released the semaphore
Unit #6 has acquired the semaphore
Unit #4 has released the semaphore
Unit #8 has acquired the semaphore
Unit #3 has released the semaphore
Unit #7 has acquired the semaphore
Unit #5 has released the semaphore
Unit #6 has released the semaphore
Unit #9 has acquired the semaphore
Unit #8 has released the semaphore
Unit #7 has released the semaphore
Unit #9 has released the semaphore
</pre>
 
=={{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.
<syntaxhighlight lang="logtalk">
:- object(metered_concurrency).
 
:- threaded.
 
:- public(run/2).
run(Workers, Max) :-
% start the semaphore and the workers
threaded_ignore(semaphore(Max, Max)),
forall(
integer::between(1, Workers, Worker),
threaded_call(worker(Worker))
),
% wait for the workers to finish
forall(
integer::between(1, Workers, Worker),
threaded_exit(worker(Worker))
),
% tell the semaphore thread to stop
threaded_notify(worker(stop, _)).
 
:- public(run/0).
run :-
% default values: 7 workers, 2 concurrent workers
run(7, 2).
 
semaphore(N, Max) :-
threaded_wait(worker(Action, Worker)),
( Action == acquire, N > 0 ->
M is N - 1,
threaded_notify(semaphore(acquired, Worker)),
semaphore(M, Max)
; Action == release ->
M is N + 1,
threaded_notify(semaphore(released, Worker)),
semaphore(M, Max)
; Action == stop ->
true
; % Action == acquire, N =:= 0,
threaded_wait(worker(release, OtherWorker)),
threaded_notify(semaphore(released, OtherWorker)),
threaded_notify(semaphore(acquired, Worker)),
semaphore(N, Max)
).
 
worker(Worker) :-
% use a random setup time for the worker
random::random(0.0, 2.0, Setup),
thread_sleep(Setup),
threaded_notify(worker(acquire, Worker)),
threaded_wait(semaphore(acquired, Worker)),
write('Worker '), write(Worker), write(' acquired semaphore\n'),
thread_sleep(2),
threaded_notify(worker(release, Worker)),
write('Worker '), write(Worker), write(' releasing semaphore\n'),
threaded_wait(semaphore(released, Worker)).
 
:- end_object.
</syntaxhighlight>
Output:
<syntaxhighlight lang="text">
| ?- metered_concurrency::run.
Worker 1 acquired semaphore
Worker 6 acquired semaphore
Worker 1 releasing semaphore
Worker 2 acquired semaphore
Worker 6 releasing semaphore
Worker 5 acquired semaphore
Worker 2 releasing semaphore
Worker 7 acquired semaphore
Worker 5 releasing semaphore
Worker 3 acquired semaphore
Worker 7 releasing semaphore
Worker 4 acquired semaphore
Worker 3 releasing semaphore
Worker 4 releasing semaphore
yes
</syntaxhighlight>
 
=={{header|Nim}}==
===Using Posix interface===
Using Posix functions is straightforward but we have chosen to encapsulate them in a more pleasant interface.
 
This program must be compiled with option <code>--threads:on</code>.
<syntaxhighlight lang="nim">import os, posix, strformat
 
type SemaphoreError = object of CatchableError
 
var
sem: Sem
running = true
 
proc init(sem: var Sem; count: Natural) =
if sem_init(sem.addr, 0, count.cint) != 0:
raise newException(SemaphoreError, "unable to initialize semaphore")
 
proc count(sem: var Sem): int =
var c: cint
if sem_getvalue(sem.addr, c) != 0:
raise newException(SemaphoreError, "unable to get value of semaphore")
result = c
 
proc acquire(sem: var Sem) =
if sem_wait(sem.addr) != 0:
raise newException(SemaphoreError, "unable to acquire semaphore")
 
proc release(sem: var Sem) =
if sem_post(sem.addr) != 0:
raise newException(SemaphoreError, "unable to get release semaphore")
 
proc close(sem: var Sem) =
if sem_destroy(sem.addr) != 0:
raise newException(SemaphoreError, "unable to close the semaphore")
 
proc task(id: int) {.thread.} =
echo &"Task {id} started."
while running:
sem.acquire()
echo &"Task {id} acquired semaphore. Count is {sem.count()}."
sleep(2000)
sem.release()
echo &"Task {id} released semaphore. Count is {sem.count()}."
sleep(100) # Give time to other tasks.
echo &"Task {id} terminated."
 
proc stop() {.noconv.} = running = false
 
 
var threads: array[10, Thread[int]]
 
sem.init(4)
setControlCHook(stop) # Catch control-C to terminate gracefully.
 
for n in 0..9: createThread(threads[n], task, n)
threads.joinThreads()
sem.close()</syntaxhighlight>
 
{{out}}
<pre>Task 0 started.
Task 0 acquired semaphore.
Task 1 started.
Task 1 acquired semaphore.
Task 2 started.
Task 2 acquired semaphore.
Task 4 started.
Task 4 acquired semaphore.
Task 5 started.
Task 6 started.
Task 8 started.
Task 3 started.
Task 9 started.
Task 7 started.
Task 1 released semaphore.
Task 5 acquired semaphore.
Task 6 acquired semaphore.
Task 0 released semaphore.
Task 2 released semaphore.
Task 8 acquired semaphore.
Task 4 released semaphore.
Task 3 acquired semaphore.
Task 5 released semaphore.
Task 9 acquired semaphore.
Task 6 released semaphore.
Task 7 acquired semaphore.
Task 8 released semaphore.
Task 1 acquired semaphore.
Task 3 released semaphore.
Task 0 acquired semaphore.
Task 9 released semaphore.
Task 2 acquired semaphore.
Task 7 released semaphore.
Task 4 acquired semaphore.
Task 1 released semaphore.
Task 5 acquired semaphore.
Task 0 released semaphore.
Task 6 acquired semaphore.
Task 9 terminated.
Task 7 terminated.
Task 1 terminated.
Task 0 terminated.
Task 2 released semaphore.
Task 8 acquired semaphore.
Task 4 released semaphore.
Task 3 acquired semaphore.
Task 5 released semaphore.
Task 6 released semaphore.
Task 2 terminated.
Task 4 terminated.
Task 5 terminated.
Task 6 terminated.
Task 8 released semaphore.
Task 3 released semaphore.
Task 8 terminated.
Task 3 terminated.</pre>
 
===Using locks and conditions===
Using Nim standard mechanisms provided by module “locks”. As for the previous program, it must be compiled with option <code>--threads:on</code>.
 
<syntaxhighlight lang="nim">import locks, os, strformat
 
type Semaphore = object
lock: Lock
cond: Cond
maxCount: int
currCount: int
 
var
sem: Semaphore
running = true
 
proc init(sem: var Semaphore; maxCount: Positive) =
sem.lock.initLock()
sem.cond.initCond()
sem.maxCount = maxCount
sem.currCount = maxCount
 
proc count(sem: var Semaphore): int =
sem.lock.acquire()
result = sem.currCount
sem.lock.release()
 
proc acquire(sem: var Semaphore) =
sem.lock.acquire()
while sem.currCount == 0:
sem.cond.wait(sem.lock)
dec sem.currCount
sem.lock.release()
 
proc release(sem: var Semaphore) =
sem.lock.acquire()
if sem.currCount < sem.maxCount:
inc sem.currCount
sem.lock.release()
sem.cond.signal()
 
proc close(sem: var Semaphore) =
sem.lock.deinitLock()
sem.cond.deinitCond()
 
proc task(id: int) {.thread.} =
echo &"Task {id} started."
while running:
sem.acquire()
echo &"Task {id} acquired semaphore."
sleep(2000)
sem.release()
echo &"Task {id} released semaphore."
sleep(100) # Give time to other tasks.
echo &"Task {id} terminated."
 
proc stop() {.noconv.} = running = false
 
 
var threads: array[10, Thread[int]]
 
sem.init(4)
setControlCHook(stop) # Catch control-C to terminate gracefully.
 
for n in 0..9: createThread(threads[n], task, n)
threads.joinThreads()
sem.close()</syntaxhighlight>
 
{{out}}
<pre>Task 0 started.
Task 0 acquired semaphore.
Task 1 started.
Task 1 acquired semaphore.
Task 2 started.
Task 3 started.
Task 2 acquired semaphore.
Task 3 acquired semaphore.
Task 4 started.
Task 5 started.
Task 6 started.
Task 7 started.
Task 8 started.
Task 9 started.
Task 0 released semaphore.
Task 4 acquired semaphore.
Task 1 released semaphore.
Task 5 acquired semaphore.
Task 2 released semaphore.
Task 6 acquired semaphore.
Task 3 released semaphore.
Task 7 acquired semaphore.
Task 4 released semaphore.
Task 8 acquired semaphore.
Task 5 released semaphore.
Task 9 acquired semaphore.
Task 6 released semaphore.
Task 0 acquired semaphore.
Task 7 released semaphore.
Task 1 acquired semaphore.
Task 8 released semaphore.
Task 2 acquired semaphore.
Task 9 released semaphore.
Task 3 acquired semaphore.
Task 0 released semaphore.
Task 4 acquired semaphore.
Task 1 released semaphore.
Task 5 acquired semaphore.
Task 8 terminated.
Task 9 terminated.
Task 0 terminated.
Task 1 terminated.
Task 2 released semaphore.
Task 6 acquired semaphore.
Task 3 released semaphore.
Task 7 acquired semaphore.
Task 4 released semaphore.
Task 5 released semaphore.
Task 2 terminated.
Task 3 terminated.
Task 5 terminated.
Task 4 terminated.
Task 6 released semaphore.
Task 7 released semaphore.
Task 6 terminated.
Task 7 terminated.</pre>
 
=={{header|Oforth}}==
 
A semaphore can be emulated with a channel starting with n objects.
Acquiring the semaphore is receiving an object from the channel
Releasing the semaphore is sending by the object into the channel.
 
If the channel is empty a task will wait until it is no more empty.
 
<syntaxhighlight lang="oforth">import: parallel
 
Object Class new: Semaphore(ch)
 
Semaphore method: initialize(n)
Channel newSize(n) dup := ch
#[ 1 over send drop ] times(n) drop ;
 
Semaphore method: acquire @ch receive drop ;
Semaphore method: release 1 @ch send drop ;</syntaxhighlight>
 
Usage :
 
<syntaxhighlight lang="oforth">: mytask(s)
while( true ) [
s acquire "Semaphore acquired" .cr
2000 sleep
s release "Semaphore released" .cr
] ;
 
: test(n)
| s i |
Semaphore new(n) ->s
10 loop: i [ #[ s mytask ] & ] ;</syntaxhighlight>
 
=={{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 723 ⟶ 1,628:
for I in 1..10 do
{StartWorker I}
end</langsyntaxhighlight>
 
=={{header|Perl}}==
See [http://search.cpan.org/dist/Coro/Coro/Semaphore.pm Coro::Semaphore].
 
=={{header|Phix}}==
{{trans|Euphoria}}
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (tasks)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">sems</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<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>
<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>
<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>
<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>
<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>
<span style="color: #008080;">else</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<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>
<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>
<span style="color: #000000;">task_suspend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">task_self</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: #0000FF;">&=</span> <span style="color: #000000;">task_self</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <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: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<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>
<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>
<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>
<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>
<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>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<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>
<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>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<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>
<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>
<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>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<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>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">worker</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">acquire</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sem</span><span style="color: #0000FF;">)</span>
<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>
<span style="color: #000000;">delay</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">release</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sem</span><span style="color: #0000FF;">)</span>
<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>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<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>
<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>
<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>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<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>
<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>
<span style="color: #000000;">task_yield</span><span style="color: #0000FF;">()</span>
<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>
<span style="color: #008080;">if</span> <span style="color: #000000;">scnew</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">sc</span>
<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>
<span style="color: #000000;">sc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">scnew</span>
<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>
<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>
<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: #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>
- Task 2 acquired semaphore.
- Task 3 acquired semaphore.
- Task 4 acquired semaphore.
- Task 5 acquired semaphore.
Semaphore count now 0
+ Task 4 released semaphore.
- Task 6 acquired semaphore.
+ Task 3 released semaphore.
- Task 7 acquired semaphore.
+ Task 2 released semaphore.
- Task 8 acquired semaphore.
+ Task 5 released semaphore.
- Task 9 acquired semaphore.
Semaphore count now 0
+ Task 9 released semaphore.
- Task 10 acquired semaphore.
+ Task 8 released semaphore.
- Task 11 acquired semaphore.
+ Task 7 released semaphore.
+ Task 6 released semaphore.
Semaphore count now 2
+ Task 11 released semaphore.
+ Task 10 released semaphore.
Semaphore count now 4
"done"
</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(let Sem (tmp "sem")
(for U 4 # Create 4 concurrent units
(unless (fork)
Line 736 ⟶ 1,745:
(wait 2000)
(prinl "Unit " U " releasing the semaphore") )
(bye) ) ) )</langsyntaxhighlight>
 
=={{header|PureBasic}}==
This launches a few threads in parallel, but restricted by the counter.
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 764 ⟶ 1,774:
WaitThread(i)
EndIf
Next</langsyntaxhighlight>
Sample output
<pre>Thread #0 active.
Line 782 ⟶ 1,792:
Python threading module includes a semaphore implementation. This code show how to use it.
 
<langsyntaxhighlight lang="python">import time
import threading
 
Line 818 ⟶ 1,828:
running = 0
for t in workers:
t.join()</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<syntaxhighlight lang="racket">
#lang racket
 
(define sema (make-semaphore 4)) ; allow 4 concurrent jobs
 
;; start 20 jobs and wait for all of them to end
(for-each
thread-wait
(for/list ([i 20])
(thread (λ() (semaphore-wait sema)
(printf "Job #~a acquired semaphore\n" i)
(sleep 2)
(printf "Job #~a done\n" i)
(semaphore-post sema)))))
</syntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
Uses a buffered channel to hand out a limited number of tickets.
<syntaxhighlight lang="raku" line>class Semaphore {
has $.tickets = Channel.new;
method new ($max) {
my $s = self.bless;
$s.tickets.send(True) xx $max;
$s;
}
method acquire { $.tickets.receive }
method release { $.tickets.send(True) }
}
 
sub MAIN ($units = 5, $max = 2) {
my $sem = Semaphore.new($max);
 
my @units = do for ^$units -> $u {
start {
$sem.acquire; say "unit $u acquired";
sleep 2;
$sem.release; say "unit $u released";
}
}
await @units;
}</syntaxhighlight>
{{out}}
<pre>unit 0 acquired
unit 1 acquired
unit 0 released
unit 1 released
unit 3 acquired
unit 2 acquired
unit 3 released
unit 2 released
unit 4 acquired
unit 4 released</pre>
 
=={{header|Raven}}==
Counting semaphores are built in:
 
<langsyntaxhighlight lang="raven"># four workers may be concurrent
4 semaphore as sem
 
Line 839 ⟶ 1,905:
group
10 each drop worker
list as workers</langsyntaxhighlight>
 
Thread joining is automatic by default.
 
=={{header|Ruby}}==
 
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.
<syntaxhighlight lang="ruby">
require 'thread'
 
# Simple Semaphore implementation
class Semaphore
def initialize(size = 1)
@queue = SizedQueue.new(size)
size.times { acquire }
end
 
def acquire
tap { @queue.push(nil) }
end
 
def release
tap { @queue.pop }
end
 
# @return [Integer]
def count
@queue.length
end
 
def synchronize
release
yield
ensure
acquire
end
end
 
def foo(id, sem)
sem.synchronize do
puts "Thread #{id} Acquired lock"
sleep(2)
end
end
 
threads = []
n = 5
s = Semaphore.new(3)
n.times do |i|
threads << Thread.new { foo i, s }
end
threads.each(&:join)
 
</syntaxhighlight>
=={{header|Rust}}==
<syntaxhighlight lang="rust">
//! Rust has a perfectly good Semaphore type already. It lacks count(), though, so we can't use it
//! directly.
 
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread::{self, spawn};
use std::time::Duration;
 
pub struct CountingSemaphore {
/// Remaining resource count
count: AtomicUsize,
 
/// How long to sleep if a resource is being contended
backoff: Duration,
}
 
pub struct CountingSemaphoreGuard<'a> {
/// A reference to the owning semaphore.
sem: &'a CountingSemaphore,
}
 
impl CountingSemaphore {
/// Create a semaphore with `max` available resources and a linearly increasing backoff of
/// `backoff` (used during spinlock contention).
pub fn new(max: usize, backoff: Duration) -> CountingSemaphore {
CountingSemaphore {
count: AtomicUsize::new(max),
backoff,
}
}
 
/// Acquire a resource, returning a RAII CountingSemaphoreGuard.
pub fn acquire(&self) -> CountingSemaphoreGuard {
// Spinlock until remaining resource count is at least 1
let mut backoff = self.backoff;
loop {
// Probably don't need SeqCst here, but it doesn't hurt.
let count = self.count.load(SeqCst);
// The check for 0 is necessary to make sure we don't go negative, which is why this
// must be a compare-and-swap rather than a straight decrement.
if count == 0
|| self
.count
.compare_exchange(count, count - 1, SeqCst, SeqCst)
.is_err()
{
// Linear backoff a la Servo's spinlock contention.
thread::sleep(backoff);
backoff += self.backoff;
} else {
// We successfully acquired the resource.
break;
}
}
CountingSemaphoreGuard { sem: self }
}
 
// Return remaining resource count
pub fn count(&self) -> usize {
self.count.load(SeqCst)
}
}
 
impl<'a> Drop for CountingSemaphoreGuard<'a> {
/// When the guard is dropped, a resource is released back to the pool.
fn drop(&mut self) {
self.sem.count.fetch_add(1, SeqCst);
}
}
 
fn metered(duration: Duration) {
static MAX_COUNT: usize = 4; // Total available resources
static NUM_WORKERS: u8 = 10; // Number of workers contending for the resources
let backoff = Duration::from_millis(1); // Linear backoff time
// Create a shared reference to the semaphore
let sem = Arc::new(CountingSemaphore::new(MAX_COUNT, backoff));
// Create a channel for notifying the main task that the workers are done
let (tx, rx) = channel();
for i in 0..NUM_WORKERS {
let sem = Arc::clone(&sem);
let tx = tx.clone();
spawn(move || {
// Acquire the resource
let guard = sem.acquire();
let count = sem.count();
// Make sure the count is legal
assert!(count < MAX_COUNT);
println!("Worker {} after acquire: count = {}", i, count);
// Sleep for `duration`
thread::sleep(duration);
// Release the resource
drop(guard);
// Make sure the count is legal
let count = sem.count();
assert!(count <= MAX_COUNT);
println!("Worker {} after release: count = {}", i, count);
// Notify the main task of completion
tx.send(()).unwrap();
});
}
drop(tx);
// Wait for all the subtasks to finish
for _ in 0..NUM_WORKERS {
rx.recv().unwrap();
}
}
 
fn main() {
// Hold each resource for 2 seconds per worker
metered(Duration::from_secs(2));
}
 
</syntaxhighlight>
{{out}}
<pre>
Worker 0 after acquire: count = 3
Worker 1 after acquire: count = 2
Worker 2 after acquire: count = 1
Worker 3 after acquire: count = 0
Worker 0 after release: count = 1
Worker 1 after release: count = 2
Worker 3 after release: count = 3
Worker 2 after release: count = 4
Worker 7 after acquire: count = 3
Worker 5 after acquire: count = 2
Worker 9 after acquire: count = 1
Worker 8 after acquire: count = 0
Worker 8 after release: count = 1
Worker 9 after release: count = 2
Worker 5 after release: count = 3
Worker 7 after release: count = 4
Worker 6 after acquire: count = 3
Worker 4 after acquire: count = 2
Worker 6 after release: count = 3
Worker 4 after release: count = 4
</pre>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">class CountingSemaphore(var maxCount: Int) {
private var lockCount = 0
 
def acquire(): Unit = {
while ( {
lockCount >= maxCount
}) wait()
lockCount += 1
}
 
def release(): Unit = {
if (lockCount > 0) {
lockCount -= 1
notifyAll()
}
}
 
def getCount: Int = lockCount
}
 
object Worker {
def main(args: Array[String]): Unit = {
val (lock, crew) = (new CountingSemaphore(3), new Array[Worker](5))
for { i <- 0 until 5} {
crew(i) = new Worker(lock, i)
crew(i).start()
}
}
}</syntaxhighlight>
 
=={{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 911 ⟶ 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 934 ⟶ 2,223:
( acquire < sem ; job 3 ; release > sem ) &
 
echo 'Initialize Jobs' >&2 ; echo '1' > sem</langsyntaxhighlight>
 
=={{header|Visual Basic .NET}}==
Line 940 ⟶ 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.
<syntaxhighlight lang="wren">import "scheduler" for Scheduler
import "timer" for Timer
import "./queue" for Queue
 
class CountingSemaphore {
construct new(numRes) {
_count = numRes
_queue = Queue.new()
}
 
count { _count }
 
acquire(task) {
if (_count > 0) {
_count = _count - 1
return true
}
_queue.push(task)
return false
}
 
release() {
if (!_queue.isEmpty) {
var task = _queue.pop()
task.transfer()
} else {
_count = _count + 1
}
}
}
 
var numRes = 3
var numTasks = 6
var tasks = List.filled(6, null)
var cs = CountingSemaphore.new(numRes)
var main = Fiber.current
 
var duty = Fn.new { |n|
System.print("Task %(n) started when count = %(cs.count).")
var acquired = cs.acquire(Fiber.current)
if (!acquired) {
System.print("Task %(n) waiting for semaphore.")
Fiber.yield() // return to calling fiber in the meantime
}
System.print("Task %(n) has acquired the semaphore.")
Scheduler.add {
// whilst this fiber is sleeping, start the next task if there is one
var next = n + 1
if (next <= numTasks) {
tasks[next-1].call(next)
}
}
Timer.sleep(2000)
System.print("Task %(n) has released the semaphore.")
cs.release()
if (n == numTasks) main.transfer() // on completion of last task, return to main fiber
}
 
// create fibers for tasks
for (i in 0..5) tasks[i] = Fiber.new(duty)
 
// call the first one
tasks[0].call(1)
System.print("\nAll %(numTasks) tasks completed!")</syntaxhighlight>
 
{{out}}
<pre>
Task 1 started when count = 3.
Task 1 has acquired the semaphore.
Task 2 started when count = 2.
Task 2 has acquired the semaphore.
Task 3 started when count = 1.
Task 3 has acquired the semaphore.
Task 4 started when count = 0.
Task 4 waiting for semaphore.
Task 1 has released the semaphore.
Task 4 has acquired the semaphore.
Task 5 started when count = 0.
Task 5 waiting for semaphore.
Task 2 has released the semaphore.
Task 5 has acquired the semaphore.
Task 6 started when count = 0.
Task 6 waiting for semaphore.
Task 3 has released the semaphore.
Task 6 has acquired the semaphore.
Task 4 has released the semaphore.
Task 5 has released the semaphore.
Task 6 has released the semaphore.
 
All 6 tasks completed!
 
real 0m4.011s
user 0m0.007s
sys 0m0.000s
</pre>
 
=={{header|zkl}}==
Semaphores are built in.
<syntaxhighlight lang="zkl">fcn job(name,sem){
name.println(" wait"); sem.acquire();
name.println(" go"); Atomic.sleep(2);
sem.release(); name.println(" done")
}
// start 3 threads using the same semphore
s:=Thread.Semaphore(1);
job.launch("1",s); job.launch("2",s); job.launch("3",s);</syntaxhighlight>
{{out}}
<pre>
2 wait
2 go
1 wait
3 wait
2 done
1 go
1 done
3 go
3 done
</pre>
 
 
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->
9,476

edits