Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
5
Task/Metered-concurrency/00-META.yaml
Normal file
5
Task/Metered-concurrency/00-META.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Metered_concurrency
|
||||
note: Concurrency
|
||||
requires:
|
||||
- Concurrency
|
||||
2
Task/Metered-concurrency/00-TASK.txt
Normal file
2
Task/Metered-concurrency/00-TASK.txt
Normal 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.
|
||||
|
||||
13
Task/Metered-concurrency/ALGOL-68/metered-concurrency.alg
Normal file
13
Task/Metered-concurrency/ALGOL-68/metered-concurrency.alg
Normal 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 )
|
||||
)
|
||||
9
Task/Metered-concurrency/Ada/metered-concurrency-1.ada
Normal file
9
Task/Metered-concurrency/Ada/metered-concurrency-1.ada
Normal 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;
|
||||
40
Task/Metered-concurrency/Ada/metered-concurrency-2.ada
Normal file
40
Task/Metered-concurrency/Ada/metered-concurrency-2.ada
Normal 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;
|
||||
37
Task/Metered-concurrency/Ada/metered-concurrency-3.ada
Normal file
37
Task/Metered-concurrency/Ada/metered-concurrency-3.ada
Normal 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;
|
||||
61
Task/Metered-concurrency/BBC-BASIC/metered-concurrency.basic
Normal file
61
Task/Metered-concurrency/BBC-BASIC/metered-concurrency.basic
Normal 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
|
||||
28
Task/Metered-concurrency/C++/metered-concurrency.cpp
Normal file
28
Task/Metered-concurrency/C++/metered-concurrency.cpp
Normal 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;
|
||||
}
|
||||
29
Task/Metered-concurrency/C-sharp/metered-concurrency.cs
Normal file
29
Task/Metered-concurrency/C-sharp/metered-concurrency.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
51
Task/Metered-concurrency/C/metered-concurrency.c
Normal file
51
Task/Metered-concurrency/C/metered-concurrency.c
Normal 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);
|
||||
}
|
||||
49
Task/Metered-concurrency/D/metered-concurrency-1.d
Normal file
49
Task/Metered-concurrency/D/metered-concurrency-1.d
Normal 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 ;
|
||||
}
|
||||
21
Task/Metered-concurrency/D/metered-concurrency-2.d
Normal file
21
Task/Metered-concurrency/D/metered-concurrency-2.d
Normal 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;
|
||||
}
|
||||
39
Task/Metered-concurrency/E/metered-concurrency.e
Normal file
39
Task/Metered-concurrency/E/metered-concurrency.e
Normal 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)
|
||||
}
|
||||
13
Task/Metered-concurrency/EchoLisp/metered-concurrency.l
Normal file
13
Task/Metered-concurrency/EchoLisp/metered-concurrency.l
Normal 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)))
|
||||
67
Task/Metered-concurrency/Erlang/metered-concurrency.erl
Normal file
67
Task/Metered-concurrency/Erlang/metered-concurrency.erl
Normal 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).
|
||||
|
|
@ -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
|
||||
12
Task/Metered-concurrency/Factor/metered-concurrency.factor
Normal file
12
Task/Metered-concurrency/Factor/metered-concurrency.factor
Normal 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
|
||||
47
Task/Metered-concurrency/FreeBASIC/metered-concurrency.basic
Normal file
47
Task/Metered-concurrency/FreeBASIC/metered-concurrency.basic
Normal 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
|
||||
45
Task/Metered-concurrency/Go/metered-concurrency-1.go
Normal file
45
Task/Metered-concurrency/Go/metered-concurrency-1.go
Normal 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
|
||||
}
|
||||
61
Task/Metered-concurrency/Go/metered-concurrency-2.go
Normal file
61
Task/Metered-concurrency/Go/metered-concurrency-2.go
Normal 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()
|
||||
}
|
||||
18
Task/Metered-concurrency/Groovy/metered-concurrency-1.groovy
Normal file
18
Task/Metered-concurrency/Groovy/metered-concurrency-1.groovy
Normal 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 }
|
||||
}
|
||||
14
Task/Metered-concurrency/Groovy/metered-concurrency-2.groovy
Normal file
14
Task/Metered-concurrency/Groovy/metered-concurrency-2.groovy
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Task/Metered-concurrency/Haskell/metered-concurrency-1.hs
Normal file
29
Task/Metered-concurrency/Haskell/metered-concurrency-1.hs
Normal 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
|
||||
17
Task/Metered-concurrency/Haskell/metered-concurrency-2.hs
Normal file
17
Task/Metered-concurrency/Haskell/metered-concurrency-2.hs
Normal 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
|
||||
13
Task/Metered-concurrency/J/metered-concurrency-1.j
Normal file
13
Task/Metered-concurrency/J/metered-concurrency-1.j
Normal 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
|
||||
}}
|
||||
11
Task/Metered-concurrency/J/metered-concurrency-2.j
Normal file
11
Task/Metered-concurrency/J/metered-concurrency-2.j
Normal 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
|
||||
31
Task/Metered-concurrency/J/metered-concurrency-3.j
Normal file
31
Task/Metered-concurrency/J/metered-concurrency-3.j
Normal 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
|
||||
}}
|
||||
6
Task/Metered-concurrency/J/metered-concurrency-4.j
Normal file
6
Task/Metered-concurrency/J/metered-concurrency-4.j
Normal 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
|
||||
59
Task/Metered-concurrency/Java/metered-concurrency.java
Normal file
59
Task/Metered-concurrency/Java/metered-concurrency.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
21
Task/Metered-concurrency/Julia/metered-concurrency.julia
Normal file
21
Task/Metered-concurrency/Julia/metered-concurrency.julia
Normal 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)
|
||||
20
Task/Metered-concurrency/Kotlin/metered-concurrency.kotlin
Normal file
20
Task/Metered-concurrency/Kotlin/metered-concurrency.kotlin
Normal 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
52
Task/Metered-concurrency/Nim/metered-concurrency-1.nim
Normal file
52
Task/Metered-concurrency/Nim/metered-concurrency-1.nim
Normal 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()
|
||||
63
Task/Metered-concurrency/Nim/metered-concurrency-2.nim
Normal file
63
Task/Metered-concurrency/Nim/metered-concurrency-2.nim
Normal 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()
|
||||
10
Task/Metered-concurrency/Oforth/metered-concurrency-1.fth
Normal file
10
Task/Metered-concurrency/Oforth/metered-concurrency-1.fth
Normal 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 ;
|
||||
11
Task/Metered-concurrency/Oforth/metered-concurrency-2.fth
Normal file
11
Task/Metered-concurrency/Oforth/metered-concurrency-2.fth
Normal 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 ] & ] ;
|
||||
60
Task/Metered-concurrency/Oz/metered-concurrency.oz
Normal file
60
Task/Metered-concurrency/Oz/metered-concurrency.oz
Normal 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
|
||||
73
Task/Metered-concurrency/Phix/metered-concurrency.phix
Normal file
73
Task/Metered-concurrency/Phix/metered-concurrency.phix
Normal 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>
|
||||
<!--
|
||||
8
Task/Metered-concurrency/PicoLisp/metered-concurrency.l
Normal file
8
Task/Metered-concurrency/PicoLisp/metered-concurrency.l
Normal 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) ) ) )
|
||||
24
Task/Metered-concurrency/PureBasic/metered-concurrency.basic
Normal file
24
Task/Metered-concurrency/PureBasic/metered-concurrency.basic
Normal 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
|
||||
37
Task/Metered-concurrency/Python/metered-concurrency.py
Normal file
37
Task/Metered-concurrency/Python/metered-concurrency.py
Normal 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()
|
||||
13
Task/Metered-concurrency/Racket/metered-concurrency.rkt
Normal file
13
Task/Metered-concurrency/Racket/metered-concurrency.rkt
Normal 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)))))
|
||||
23
Task/Metered-concurrency/Raku/metered-concurrency.raku
Normal file
23
Task/Metered-concurrency/Raku/metered-concurrency.raku
Normal 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;
|
||||
}
|
||||
17
Task/Metered-concurrency/Raven/metered-concurrency.raven
Normal file
17
Task/Metered-concurrency/Raven/metered-concurrency.raven
Normal 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
|
||||
44
Task/Metered-concurrency/Ruby/metered-concurrency.rb
Normal file
44
Task/Metered-concurrency/Ruby/metered-concurrency.rb
Normal 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)
|
||||
113
Task/Metered-concurrency/Rust/metered-concurrency.rust
Normal file
113
Task/Metered-concurrency/Rust/metered-concurrency.rust
Normal 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));
|
||||
}
|
||||
30
Task/Metered-concurrency/Scala/metered-concurrency.scala
Normal file
30
Task/Metered-concurrency/Scala/metered-concurrency.scala
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Task/Metered-concurrency/Tcl/metered-concurrency.tcl
Normal file
66
Task/Metered-concurrency/Tcl/metered-concurrency.tcl
Normal 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
|
||||
}
|
||||
19
Task/Metered-concurrency/UnixPipes/metered-concurrency.up
Normal file
19
Task/Metered-concurrency/UnixPipes/metered-concurrency.up
Normal 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
|
||||
|
|
@ -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
|
||||
64
Task/Metered-concurrency/Wren/metered-concurrency.wren
Normal file
64
Task/Metered-concurrency/Wren/metered-concurrency.wren
Normal 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!")
|
||||
8
Task/Metered-concurrency/Zkl/metered-concurrency.zkl
Normal file
8
Task/Metered-concurrency/Zkl/metered-concurrency.zkl
Normal 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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue