Data commit

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

View file

@ -0,0 +1,5 @@
---
from: http://rosettacode.org/wiki/Metered_concurrency
note: Concurrency
requires:
- Concurrency

View file

@ -0,0 +1,2 @@
The goal of this task is to create a [[wp:Counting semaphore|counting semaphore]] used to control the execution of a set of concurrent units. This task intends to demonstrate coordination of active concurrent units through the use of a passive concurrent unit. The operations for a counting semaphore are ''acquire'', ''release'', and ''count''. Each active concurrent unit should attempt to acquire the counting semaphore before executing its assigned duties. In this case the active concurrent unit should report that it has acquired the semaphore. It should sleep for 2 seconds and then release the semaphore.

View file

@ -0,0 +1,13 @@
SEMA sem = LEVEL 1;
PROC job = (INT n)VOID: (
printf(($" Job "d" acquired Semaphore ..."$,n));
TO 10000000 DO SKIP OD;
printf(($" Job "d" releasing Semaphore"l$,n))
);
PAR (
( DOWN sem ; job(1) ; UP sem ) ,
( DOWN sem ; job(2) ; UP sem ) ,
( DOWN sem ; job(3) ; UP sem )
)

View file

@ -0,0 +1,9 @@
package Semaphores is
protected type Counting_Semaphore(Max : Positive) is
entry Acquire;
procedure Release;
function Count return Natural;
private
Lock_Count : Natural := 0;
end Counting_Semaphore;
end Semaphores;

View file

@ -0,0 +1,40 @@
package body Semaphores is
------------------------
-- Counting_Semaphore --
------------------------
protected body Counting_Semaphore is
-------------
-- Acquire --
-------------
entry Acquire when Lock_Count < Max is
begin
Lock_Count := Lock_Count + 1;
end Acquire;
-----------
-- Count --
-----------
function Count return Natural is
begin
return Lock_Count;
end Count;
-------------
-- Release --
-------------
procedure Release is
begin
if Lock_Count > 0 then
Lock_Count := Lock_Count - 1;
end if;
end Release;
end Counting_Semaphore;
end Semaphores;

View file

@ -0,0 +1,37 @@
with Semaphores;
with Ada.Text_Io; use Ada.Text_Io;
procedure Semaphores_Main is
-- Create an instance of a Counting_Semaphore with Max set to 3
Lock : Semaphores.Counting_Semaphore(3);
-- Define a task type to interact with the Lock object declared above
task type Worker is
entry Start (Sleep : in Duration; Id : in Positive);
end Worker;
task body Worker is
Sleep_Time : Duration;
My_Id : Positive;
begin
accept Start(Sleep : in Duration; Id : in Positive) do
My_Id := Id;
Sleep_Time := Sleep;
end Start;
--Acquire the lock. The task will suspend until the Acquire call completes
Lock.Acquire;
Put_Line("Task #" & Positive'Image(My_Id) & " acquired the lock.");
-- Suspend the task for Sleep_Time seconds
delay Sleep_Time;
-- Release the lock. Release is unconditional and happens without suspension
Lock.Release;
end Worker;
-- Create an array of 5 Workers
type Staff is array(Positive range 1..5) of Worker;
Crew : Staff;
begin
for I in Crew'range loop
Crew(I).Start(2.0, I);
end loop;
end Semaphores_Main;

View file

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

View file

@ -0,0 +1,28 @@
#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;
}

View file

@ -0,0 +1,29 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace RosettaCode
{
internal sealed class Program
{
private static void Worker(object arg, int id)
{
var sem = arg as SemaphoreSlim;
sem.Wait();
Console.WriteLine("Thread {0} has a semaphore & is now working.", id);
Thread.Sleep(2*1000);
Console.WriteLine("#{0} done.", id);
sem.Release();
}
private static void Main()
{
var semaphore = new SemaphoreSlim(Environment.ProcessorCount*2, int.MaxValue);
Console.WriteLine("You have {0} processors availiabe", Environment.ProcessorCount);
Console.WriteLine("This program will use {0} semaphores.\n", semaphore.CurrentCount);
Parallel.For(0, Environment.ProcessorCount*3, y => Worker(semaphore, y));
}
}
}

View file

@ -0,0 +1,51 @@
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
sem_t sem;
int count = 3;
/* the whole point of a semaphore is that you don't count it:
* p/v are atomic. Unless it's locked while you are doing
* something with the count, the value is only informative */
#define getcount() count
void acquire()
{
sem_wait(&sem);
count--;
}
void release()
{
count++;
sem_post(&sem);
}
void* work(void * id)
{
int i = 10;
while (i--) {
acquire();
printf("#%d acquired sema at %d\n", *(int*)id, getcount());
usleep(rand() % 4000000); /* sleep 2 sec on average */
release();
usleep(0); /* effectively yield */
}
return 0;
}
int main()
{
pthread_t th[4];
int i, ids[] = {1, 2, 3, 4};
sem_init(&sem, 0, count);
for (i = 4; i--;) pthread_create(th + i, 0, work, ids + i);
for (i = 4; i--;) pthread_join(th[i], 0);
printf("all workers done\n");
return sem_destroy(&sem);
}

View file

@ -0,0 +1,49 @@
module meteredconcurrency ;
import std.stdio ;
import std.thread ;
import std.c.time ;
class Semaphore {
private int lockCnt, maxCnt ;
this(int count) { maxCnt = lockCnt = count ;}
void acquire() {
if(lockCnt < 0 || maxCnt <= 0)
throw new Exception("Negative Lock or Zero init. Lock") ;
while(lockCnt == 0)
Thread.getThis.yield ; // let other threads release lock
synchronized lockCnt-- ;
}
void release() {
synchronized
if (lockCnt < maxCnt)
lockCnt++ ;
else
throw new Exception("Release lock before acquire") ;
}
int getCnt() { synchronized return lockCnt ; }
}
class Worker : Thread {
private static int Id = 0 ;
private Semaphore lock ;
private int myId ;
this (Semaphore l) { super() ; lock = l ; myId = Id++ ; }
override int run() {
lock.acquire ;
writefln("Worker %d got a lock(%d left).", myId, lock.getCnt) ;
msleep(2000) ; // wait 2.0 sec
lock.release ;
writefln("Worker %d released a lock(%d left).", myId, lock.getCnt) ;
return 0 ;
}
}
void main() {
Worker[10] crew ;
Semaphore lock = new Semaphore(4) ;
foreach(inout c ; crew)
(c = new Worker(lock)).start ;
foreach(inout c ; crew)
c.wait ;
}

View file

@ -0,0 +1,21 @@
module metered;
import tools.threads, tools.log, tools.time, tools.threadpool;
void main() {
log_threads = false;
auto done = new Semaphore, lock = new Semaphore(4);
auto tp = new Threadpool(10);
for (int i = 0; i < 10; ++i) {
tp.addTask(i /apply/ (int i) {
scope(exit) done.release;
lock.acquire;
logln(i, ": lock acquired");
sleep(2.0);
lock.release;
logln(i, ": lock released");
});
}
for (int i = 0; i < 10; ++i)
done.acquire;
}

View file

@ -0,0 +1,39 @@
def makeSemaphore(maximum :(int > 0)) {
var current := 0
def waiters := <elib:vat.makeQueue>()
def notify() {
while (current < maximum && waiters.hasMoreElements()) {
current += 1
waiters.optDequeue().resolve(def released)
when (released) -> {
current -= 1
notify()
}
}
}
def semaphore {
to acquire() {
waiters.enqueue(def response)
notify()
return response
}
to count() { return current }
}
return semaphore
}
def work(label, interval, semaphore, timer, println) {
when (def releaser := semaphore <- acquire()) -> {
println(`$label: I have acquired the lock.`)
releaser.resolve(
timer.whenPast(timer.now() + interval, fn {
println(`$label: I will have released the lock.`)
})
)
}
}
def semaphore := makeSemaphore(3)
for i in 1..5 {
work(i, 2000, semaphore, timer, println)
}

View file

@ -0,0 +1,13 @@
(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)))

View file

@ -0,0 +1,67 @@
-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).

View file

@ -0,0 +1,65 @@
sequence sems
sems = {}
constant COUNTER = 1, QUEUE = 2
function semaphore(integer n)
if n > 0 then
sems = append(sems,{n,{}})
return length(sems)
else
return 0
end if
end function
procedure acquire(integer id)
if sems[id][COUNTER] = 0 then
task_suspend(task_self())
sems[id][QUEUE] &= task_self()
task_yield()
end if
sems[id][COUNTER] -= 1
end procedure
procedure release(integer id)
sems[id][COUNTER] += 1
if length(sems[id][QUEUE])>0 then
task_schedule(sems[id][QUEUE][1],1)
sems[id][QUEUE] = sems[id][QUEUE][2..$]
end if
end procedure
function count(integer id)
return sems[id][COUNTER]
end function
procedure delay(atom delaytime)
atom t
t = time()
while time() - t < delaytime do
task_yield()
end while
end procedure
integer sem
procedure worker()
acquire(sem)
printf(1,"- Task %d acquired semaphore.\n",task_self())
delay(2)
release(sem)
printf(1,"+ Task %d released semaphore.\n",task_self())
end procedure
integer task
sem = semaphore(4)
for i = 1 to 10 do
task = task_create(routine_id("worker"),{})
task_schedule(task,1)
task_yield()
end for
while length(task_list())>1 do
task_yield()
end while

View file

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

View file

@ -0,0 +1,47 @@
#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

View file

@ -0,0 +1,45 @@
package main
import (
"log"
"os"
"sync"
"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)
// WaitGroup used to wait for all students to have studied
// before terminating program
var studied sync.WaitGroup
studied.Add(nStudents)
// nStudents run concurrently
for i := 0; i < nStudents; i++ {
go student(rooms, &studied)
}
studied.Wait()
}
func student(rooms sem, studied *sync.WaitGroup) {
rooms.acquire()
// report per task descrption. also exercise count operation
fmt.Printf("Room entered. Count is %d. Studying...\n",
rooms.count())
time.Sleep(2 * time.Second) // sleep per task description
rooms.release()
studied.Done() // signal that student is done
}

View file

@ -0,0 +1,61 @@
package main
import (
"log"
"os"
"sync"
"time"
)
var fmt = log.New(os.Stdout, "", 0)
type countSem struct {
int
sync.Cond
}
func newCount(n int) *countSem {
return &countSem{n, sync.Cond{L: &sync.Mutex{}}}
}
func (cs *countSem) count() int {
cs.L.Lock()
c := cs.int
cs.L.Unlock()
return c
}
func (cs *countSem) acquire() {
cs.L.Lock()
cs.int--
for cs.int < 0 {
cs.Wait()
}
cs.L.Unlock()
}
func (cs *countSem) release() {
cs.L.Lock()
cs.int++
cs.L.Unlock()
cs.Broadcast()
}
func main() {
librarian := newCount(10)
nStudents := 20
var studied sync.WaitGroup
studied.Add(nStudents)
for i := 0; i < nStudents; i++ {
go student(librarian, &studied)
}
studied.Wait()
}
func student(studyRoom *countSem, studied *sync.WaitGroup) {
studyRoom.acquire()
fmt.Printf("Room entered. Count is %d. Studying...\n", studyRoom.count())
time.Sleep(2 * time.Second)
studyRoom.release()
studied.Done()
}

View file

@ -0,0 +1,18 @@
class CountingSemaphore {
private int count = 0
private final int max
CountingSemaphore(int max) { this.max = max }
synchronized int acquire() {
while (count >= max) { wait() }
++count
}
synchronized int release() {
if (count) { count--; notifyAll() }
count
}
synchronized int getCount() { count }
}

View file

@ -0,0 +1,14 @@
def cs = new CountingSemaphore(4)
(1..12).each { threadID ->
Thread.start {
def id = "Thread #${(threadID as String).padLeft(2,'0')}"
try {
def sCount = cs.acquire()
println("${id} has acquired Semaphore at count = ${sCount}")
sleep(2000)
} finally {
println("${id} is releasing Semaphore at count = ${cs.count}")
cs.release()
}
}
}

View file

@ -0,0 +1,29 @@
import Control.Concurrent
( newQSem,
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 >>= putStrLn

View file

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

View file

@ -0,0 +1,13 @@
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
}}

View file

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

View file

@ -0,0 +1,31 @@
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
}}

View file

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

View file

@ -0,0 +1,59 @@
public class CountingSemaphore{
private int lockCount = 0;
private int maxCount;
CountingSemaphore(int Max){
maxCount = Max;
}
public synchronized void acquire() throws InterruptedException{
while( lockCount >= maxCount){
wait();
}
lockCount++;
}
public synchronized void release(){
if (lockCount > 0)
{
lockCount--;
notifyAll();
}
}
public synchronized int getCount(){
return lockCount;
}
}
public class Worker extends Thread{
private CountingSemaphore lock;
private int id;
Worker(CountingSemaphore coordinator, int num){
lock = coordinator;
id = num;
}
Worker(){
}
public void run(){
try{
lock.acquire();
System.out.println("Worker " + id + " has acquired the lock.");
sleep(2000);
}
catch (InterruptedException e){
}
finally{
lock.release();
}
}
public static void main(String[] args){
CountingSemaphore lock = new CountingSemaphore(3);
Worker crew[];
crew = new Worker[5];
for (int i = 0; i < 5; i++){
crew[i] = new Worker(lock, i);
crew[i].start();
}
}
}

View file

@ -0,0 +1,21 @@
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)

View file

@ -0,0 +1,20 @@
// 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")
}
}
}

View file

@ -0,0 +1,57 @@
:- 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.

View file

@ -0,0 +1,16 @@
| ?- 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

View file

@ -0,0 +1,52 @@
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()

View file

@ -0,0 +1,63 @@
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()

View file

@ -0,0 +1,10 @@
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 ;

View file

@ -0,0 +1,11 @@
: 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 ] & ] ;

View file

@ -0,0 +1,60 @@
declare
fun {NewSemaphore N}
sem(max:N count:{NewCell 0} 'lock':{NewLock} sync:{NewCell _})
end
proc {Acquire Sem=sem(max:N count:C 'lock':L sync:S)}
Sync
Acquired
in
lock L then
if @C < N then
C := @C + 1
Acquired = true
else
Sync = @S
Acquired = false
end
end
if {Not Acquired} then
{Wait Sync}
{Acquire Sem}
end
end
proc {Release sem(count:C 'lock':L sync:S ...)}
lock L then
C := @C - 1
@S = unit %% wake up waiting threads
S := _ %% prepare for new waiters
end
end
proc {WithSemaphore Sem Proc}
{Acquire Sem}
try
{Proc}
finally
{Release Sem}
end
end
S = {NewSemaphore 4}
proc {StartWorker Name}
thread
for do
{WithSemaphore S
proc {$}
{System.showInfo Name#" acquired semaphore"}
{Delay 2000}
end
}
{Delay 100}
end
end
end
in
for I in 1..10 do
{StartWorker I}
end

View file

@ -0,0 +1,73 @@
(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>
<!--

View file

@ -0,0 +1,8 @@
(let Sem (tmp "sem")
(for U 4 # Create 4 concurrent units
(unless (fork)
(ctl Sem
(prinl "Unit " U " aquired the semaphore")
(wait 2000)
(prinl "Unit " U " releasing the semaphore") )
(bye) ) ) )

View file

@ -0,0 +1,24 @@
#Threads=10
#Parallels=3
Global Semaphore=CreateSemaphore(#Parallels)
Procedure Worker(*arg.i)
WaitSemaphore(Semaphore)
Debug "Thread #"+Str(*arg)+" active."
Delay(Random(2000))
SignalSemaphore(Semaphore)
EndProcedure
; Start a multi-thread based work
Dim thread(#Threads)
For i=0 To #Threads
thread(i)=CreateThread(@Worker(),i)
Next
Debug "Launcher done."
; Wait for all threads to finish before closing down
For i=0 To #Threads
If IsThread(i)
WaitThread(i)
EndIf
Next

View file

@ -0,0 +1,37 @@
import time
import threading
# Only 4 workers can run in the same time
sem = threading.Semaphore(4)
workers = []
running = 1
def worker():
me = threading.currentThread()
while 1:
sem.acquire()
try:
if not running:
break
print '%s acquired semaphore' % me.getName()
time.sleep(2.0)
finally:
sem.release()
time.sleep(0.01) # Let others acquire
# Start 10 workers
for i in range(10):
t = threading.Thread(name=str(i), target=worker)
workers.append(t)
t.start()
# Main loop
try:
while 1:
time.sleep(0.1)
except KeyboardInterrupt:
running = 0
for t in workers:
t.join()

View file

@ -0,0 +1,13 @@
#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)))))

View file

@ -0,0 +1,23 @@
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;
}

View file

@ -0,0 +1,17 @@
# four workers may be concurrent
4 semaphore as sem
thread worker
5 each as i
sem acquire
# tid is thread id
tid "%d acquired semaphore\n" print
2000 ms
sem release
# let others acquire
100 ms
# start 10 threads
group
10 each drop worker
list as workers

View file

@ -0,0 +1,44 @@
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)

View file

@ -0,0 +1,113 @@
//! 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));
}

View file

@ -0,0 +1,30 @@
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()
}
}
}

View file

@ -0,0 +1,66 @@
package require Tcl 8.6
package require Thread
# Create the global shared state of the semaphore
set handle semaphore0
tsv::set $handle mutex [thread::mutex create]
tsv::set $handle cv [thread::cond create]
tsv::set $handle count 0
tsv::set $handle max 3
# Make five worker tasks
for {set i 0} {$i<5} {incr i} {
lappend threads [thread::create -preserved {
# Not bothering to wrap this in an object for demonstration
proc init {handle} {
global mutex cv count max
set mutex [tsv::object $handle mutex]
set cv [tsv::object $handle cv]
set count [tsv::object $handle count]
set max [tsv::get $handle max]
}
proc acquire {} {
global mutex cv count max
thread::mutex lock [$mutex get]
while {[$count get] >= $max} {
thread::cond wait [$cv get] [$mutex get]
}
$count incr
thread::mutex unlock [$mutex get]
}
proc release {} {
global mutex cv count max
thread::mutex lock [$mutex get]
if {[$count get] > 0} {
$count incr -1
thread::cond notify [$cv get]
}
thread::mutex unlock [$mutex get]
}
# The core task of the worker
proc run {handle id} {
init $handle
acquire
puts "worker $id has acquired the lock"
after 2000
release
puts "worker $id is done"
}
# Wait for further instructions from the main thread
thread::wait
}]
}
# Start the workers doing useful work, giving each a unique id for pretty printing
set i 0
foreach t $threads {
puts "starting thread [incr i]"
thread::send -async $t [list run $handle $i]
}
# Wait for all the workers to finish
foreach t $threads {
thread::release -wait $t
}

View file

@ -0,0 +1,19 @@
rm -f sem ; mkfifo sem
acquire() {
x='';while test -z "$x"; do read x; done;
}
release() {
echo '1'
}
job() {
n=$1; echo "Job $n acquired Semaphore">&2 ; sleep 2; echo "Job $n released Semaphore">&2 ;
}
( acquire < sem ; job 1 ; release > sem ) &
( acquire < sem ; job 2 ; release > sem ) &
( acquire < sem ; job 3 ; release > sem ) &
echo 'Initialize Jobs' >&2 ; echo '1' > sem

View file

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

View file

@ -0,0 +1,64 @@
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!")

View file

@ -0,0 +1,8 @@
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);