A-M baby
This commit is contained in:
parent
764da6cbbb
commit
db842d013d
19005 changed files with 197040 additions and 7 deletions
1
Task/Metered-concurrency/0DESCRIPTION
Normal file
1
Task/Metered-concurrency/0DESCRIPTION
Normal file
|
|
@ -0,0 +1 @@
|
|||
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.
|
||||
4
Task/Metered-concurrency/1META.yaml
Normal file
4
Task/Metered-concurrency/1META.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
note: Concurrency
|
||||
requires:
|
||||
- Concurrency
|
||||
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.bbc
Normal file
61
Task/Metered-concurrency/BBC-BASIC/metered-concurrency.bbc
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
|
||||
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)
|
||||
}
|
||||
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
|
||||
42
Task/Metered-concurrency/Go/metered-concurrency-1.go
Normal file
42
Task/Metered-concurrency/Go/metered-concurrency-1.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// log package serializes output
|
||||
var fmt = log.New(os.Stdout, "", 0)
|
||||
|
||||
// library analogy per WP article
|
||||
const nRooms = 10
|
||||
const nStudents = 20
|
||||
|
||||
func main() {
|
||||
// buffered channel used as a counting semaphore
|
||||
rooms := make(chan int, nRooms)
|
||||
for i := 0; i < nRooms; i++ {
|
||||
rooms <- 1
|
||||
}
|
||||
// WaitGroup used to wait for all students to have studied
|
||||
// before terminating program
|
||||
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 chan int, studied *sync.WaitGroup) {
|
||||
<-rooms // acquire operation
|
||||
// report per task descrption. also exercise count operation
|
||||
fmt.Printf("Room entered. Count is %d. Studying...\n",
|
||||
len(rooms)) // len function provides count operation
|
||||
time.Sleep(2 * time.Second) // sleep per task description
|
||||
rooms <- 1 // release operation
|
||||
studied.Done() // signal that student is done
|
||||
}
|
||||
60
Task/Metered-concurrency/Go/metered-concurrency-2.go
Normal file
60
Task/Metered-concurrency/Go/metered-concurrency-2.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var fmt = log.New(os.Stdout, "", 0)
|
||||
|
||||
type countSem struct {
|
||||
c int32
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
func newCount(n int) *countSem {
|
||||
return &countSem{int32(n), sync.NewCond(new(sync.Mutex))}
|
||||
}
|
||||
|
||||
func (cs *countSem) count() int {
|
||||
return int(atomic.LoadInt32(&cs.c))
|
||||
}
|
||||
|
||||
func (cs *countSem) acquire() {
|
||||
if atomic.AddInt32(&cs.c, -1) < 0 {
|
||||
atomic.AddInt32(&cs.c, 1)
|
||||
cs.cond.L.Lock()
|
||||
for atomic.AddInt32(&cs.c, -1) < 0 {
|
||||
atomic.AddInt32(&cs.c, 1)
|
||||
cs.cond.Wait()
|
||||
}
|
||||
cs.cond.L.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *countSem) release() {
|
||||
atomic.AddInt32(&cs.c, 1)
|
||||
cs.cond.Signal()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
56
Task/Metered-concurrency/Go/metered-concurrency-3.go
Normal file
56
Task/Metered-concurrency/Go/metered-concurrency-3.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var fmt = log.New(os.Stdout, "", 0)
|
||||
|
||||
func main() {
|
||||
// three operations per task description
|
||||
acquire := make(chan int)
|
||||
release := make(chan int)
|
||||
count := make(chan chan int)
|
||||
|
||||
// library analogy per WP article
|
||||
go librarian(acquire, release, count, 10)
|
||||
nStudents := 20
|
||||
var studied sync.WaitGroup
|
||||
studied.Add(nStudents)
|
||||
for i := 0; i < nStudents; i++ {
|
||||
go student(acquire, release, count, &studied)
|
||||
}
|
||||
// wait until all students have studied before terminating program
|
||||
studied.Wait()
|
||||
}
|
||||
|
||||
func librarian(a, r chan int, c chan chan int, count int) {
|
||||
p := a // acquire operation is served or not depending on count
|
||||
for {
|
||||
select {
|
||||
case <-p: // acquire/p/wait operation
|
||||
count--
|
||||
if count == 0 {
|
||||
p = nil
|
||||
}
|
||||
case <-r: // release/v operation
|
||||
count++
|
||||
p = a
|
||||
case cc := <-c: // count operation
|
||||
cc <- count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func student(a, r chan int, c chan chan int, studied *sync.WaitGroup) {
|
||||
cc := make(chan int)
|
||||
a <- 0 // acquire
|
||||
c <- cc // request count
|
||||
fmt.Printf("Room entered. Count is %d. Studying...\n", <-cc)
|
||||
time.Sleep(2 * time.Second) // sleep per task description
|
||||
r <- 0 // release
|
||||
studied.Done() // signal done
|
||||
}
|
||||
19
Task/Metered-concurrency/Haskell/metered-concurrency.hs
Normal file
19
Task/Metered-concurrency/Haskell/metered-concurrency.hs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import Control.Concurrent
|
||||
import Control.Monad
|
||||
|
||||
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 >>= print
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
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) ) ) )
|
||||
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()
|
||||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue