Metered concurrency: Difference between revisions

Content added Content deleted
(omit m4)
m (Fixed lang tags.)
Line 6: Line 6:


The interface for the counting semaphore is defined in an Ada package specification:
The interface for the counting semaphore is defined in an Ada package specification:
<lang ada> package Semaphores is
<lang ada>package Semaphores is
protected type Counting_Semaphore(Max : Positive) is
protected type Counting_Semaphore(Max : Positive) is
entry Acquire;
entry Acquire;
procedure Release;
procedure Release;
function Count return Natural;
function Count return Natural;
private
private
Lock_Count : Natural := 0;
Lock_Count : Natural := 0;
end Counting_Semaphore;
end Counting_Semaphore;
end Semaphores;</lang>
end Semaphores;</lang>
The ''Acquire'' entry has a condition associated with it. A task can only execute the ''Acquire'' entry when ''Lock_Count'' is less than ''Max''. This is the key to making this structure behave as a counting semaphore. This condition, and all the other aspects of ''Counting_Semaphore'' are contained in the package body.
The ''Acquire'' entry has a condition associated with it. A task can only execute the ''Acquire'' entry when ''Lock_Count'' is less than ''Max''. This is the key to making this structure behave as a counting semaphore. This condition, and all the other aspects of ''Counting_Semaphore'' are contained in the package body.
<lang ada> package body Semaphores is
<lang ada>package body Semaphores is

------------------------
------------------------
-- Counting_Semaphore --
-- Counting_Semaphore --
------------------------
------------------------

protected body Counting_Semaphore is
protected body Counting_Semaphore is

-------------
-------------
-- Acquire --
-- Acquire --
-------------
-------------

entry Acquire when Lock_Count < Max is
entry Acquire when Lock_Count < Max is
begin
begin
Lock_Count := Lock_Count + 1;
Lock_Count := Lock_Count + 1;
end Acquire;
end Acquire;

-----------
-----------
-- Count --
-- Count --
-----------
-----------

function Count return Natural is
function Count return Natural is
begin
begin
return Lock_Count;
return Lock_Count;
end Count;
end Count;

-------------
-------------
-- Release --
-- Release --
-------------
-------------

procedure Release is
procedure Release is
begin
begin
if Lock_Count > 0 then
if Lock_Count > 0 then
Lock_Count := Lock_Count - 1;
Lock_Count := Lock_Count - 1;
end if;
end if;
end Release;
end Release;

end Counting_Semaphore;
end Counting_Semaphore;

end Semaphores;</lang>
end Semaphores;</lang>
We now need a set of tasks to properly call an instance of ''Counting_Semaphore''.
We now need a set of tasks to properly call an instance of ''Counting_Semaphore''.
<lang ada> with Semaphores;
<lang ada>with Semaphores;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Text_Io; use Ada.Text_Io;

procedure Semaphores_Main is
procedure Semaphores_Main is
-- Create an instance of a Counting_Semaphore with Max set to 3
-- Create an instance of a Counting_Semaphore with Max set to 3
Lock : Semaphores.Counting_Semaphore(3);
Lock : Semaphores.Counting_Semaphore(3);

-- Define a task type to interact with the Lock object declared above
-- Define a task type to interact with the Lock object declared above
task type Worker is
task type Worker is
entry Start (Sleep : in Duration; Id : in Positive);
entry Start (Sleep : in Duration; Id : in Positive);
end Worker;
end Worker;

task body Worker is
task body Worker is
Sleep_Time : Duration;
Sleep_Time : Duration;
My_Id : Positive;
My_Id : Positive;
begin
begin
accept Start(Sleep : in Duration; Id : in Positive) do
accept Start(Sleep : in Duration; Id : in Positive) do
My_Id := Id;
My_Id := Id;
Sleep_Time := Sleep;
Sleep_Time := Sleep;
end Start;
end Start;
--Acquire the lock. The task will suspend until the Acquire call completes
--Acquire the lock. The task will suspend until the Acquire call completes
Lock.Acquire;
Lock.Acquire;
Put_Line("Task #" & Positive'Image(My_Id) & " acquired the lock.");
Put_Line("Task #" & Positive'Image(My_Id) & " acquired the lock.");
-- Suspend the task for Sleep_Time seconds
-- Suspend the task for Sleep_Time seconds
delay Sleep_Time;
delay Sleep_Time;
-- Release the lock. Release is unconditional and happens without suspension
-- Release the lock. Release is unconditional and happens without suspension
Lock.Release;
Lock.Release;
end Worker;
end Worker;

-- Create an array of 5 Workers
-- Create an array of 5 Workers
type Staff is array(Positive range 1..5) of Worker;
type Staff is array(Positive range 1..5) of Worker;
Crew : Staff;
Crew : Staff;
begin
begin
for I in Crew'range loop
for I in Crew'range loop
Crew(I).Start(2.0, I);
Crew(I).Start(2.0, I);
end loop;
end loop;
end Semaphores_Main;</lang>
end Semaphores_Main;</lang>


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
SEMA sem = LEVEL 1;
<lang algol68>SEMA sem = LEVEL 1;

PROC job = (INT n)VOID: (
PROC job = (INT n)VOID: (
printf(($" Job "d" acquired Semaphore ..."$,n));
printf(($" Job "d" acquired Semaphore ..."$,n));
TO 10000000 DO SKIP OD;
TO 10000000 DO SKIP OD;
printf(($" Job "d" releasing Semaphore"l$,n))
printf(($" Job "d" releasing Semaphore"l$,n))
);
);

PAR (
PAR (
( DOWN sem ; job(1) ; UP sem ) ,
( DOWN sem ; job(1) ; UP sem ) ,
( DOWN sem ; job(2) ; UP sem ) ,
( DOWN sem ; job(2) ; UP sem ) ,
( DOWN sem ; job(3) ; UP sem )
( DOWN sem ; job(3) ; UP sem )
)</lang>
)
Output:
Output:
Job 1 acquired Semaphore ... Job 1 releasing Semaphore
<lang algol68>Job 1 acquired Semaphore ... Job 1 releasing Semaphore
Job 3 acquired Semaphore ... Job 3 releasing Semaphore
Job 3 acquired Semaphore ... Job 3 releasing Semaphore
Job 2 acquired Semaphore ... Job 2 releasing Semaphore
Job 2 acquired Semaphore ... Job 2 releasing Semaphore</lang>


=={{header|C}}==
=={{header|C}}==
Line 259: Line 259:
===Phobos with tools===
===Phobos with tools===
Using the scrapple.tools extension library for Phobos ..
Using the scrapple.tools extension library for Phobos ..
<lang d>
<lang d>module metered;
module metered;


import tools.threads, tools.log, tools.time, tools.threadpool;
import tools.threads, tools.log, tools.time, tools.threadpool;
Line 280: Line 279:
for (int i = 0; i < 10; ++i)
for (int i = 0; i < 10; ++i)
done.acquire;
done.acquire;
}</lang>
}
</lang>
=={{header|E}}==
=={{header|E}}==
This semaphore slightly differs from the task description; the release operation is not on the semaphore itself but given out with each acquisition, and cannot be invoked too many times.
This semaphore slightly differs from the task description; the release operation is not on the semaphore itself but given out with each acquisition, and cannot be invoked too many times.


def makeSemaphore(maximum :(int > 0)) {
<lang e>def makeSemaphore(maximum :(int > 0)) {
var current := 0
var current := 0
def waiters := <elib:vat.makeQueue>()
def waiters := <elib:vat.makeQueue>()
def notify() {
def notify() {
while (current < maximum && waiters.hasMoreElements()) {
while (current < maximum && waiters.hasMoreElements()) {
current += 1
current += 1
waiters.optDequeue().resolve(def released)
waiters.optDequeue().resolve(def released)
when (released) -> {
when (released) -> {
current -= 1
current -= 1
notify()
notify()
}
}
}
}
}
}
def semaphore {
def semaphore {
to acquire() {
to acquire() {
waiters.enqueue(def response)
waiters.enqueue(def response)
notify()
notify()
return response
return response
}
}
to count() { return current }
to count() { return current }
}
}
return semaphore
return semaphore
}
}

def work(label, interval, semaphore, timer, println) {
def work(label, interval, semaphore, timer, println) {
when (def releaser := semaphore <- acquire()) -> {
when (def releaser := semaphore <- acquire()) -> {
println(`$label: I have acquired the lock.`)
println(`$label: I have acquired the lock.`)
releaser.resolve(
releaser.resolve(
timer.whenPast(timer.now() + interval, fn {
timer.whenPast(timer.now() + interval, fn {
println(`$label: I will have released the lock.`)
println(`$label: I will have released the lock.`)
})
})
)
)
}
}
}
}

def semaphore := makeSemaphore(3)
def semaphore := makeSemaphore(3)
for i in 1..5 {
for i in 1..5 {
work(i, 2000, semaphore, timer, println)
work(i, 2000, semaphore, timer, println)
}</lang>
}


=={{header|Java}}==
=={{header|Java}}==
Line 392: Line 390:
Python threading module includes a semaphore implementation. This code show how to use it.
Python threading module includes a semaphore implementation. This code show how to use it.


<lang python>import time
<pre>
import time
import threading
import threading


Line 429: Line 426:
running = 0
running = 0
for t in workers:
for t in workers:
t.join()
t.join()</lang>
</pre>


=={{header|Raven}}==
=={{header|Raven}}==
Counting semaphores are built in:
Counting semaphores are built in:


# four workers may be concurrent
<lang raven># four workers may be concurrent
4 semaphore as sem
4 semaphore as sem

thread worker
thread worker
5 each as i
5 each as i
sem acquire
sem acquire
# tid is thread id
# tid is thread id
tid "%d acquired semaphore\n" print
tid "%d acquired semaphore\n" print
2000 ms
2000 ms
sem release
sem release
# let others acquire
# let others acquire
100 ms
100 ms

# start 10 threads
# start 10 threads
group
group
10 each drop worker
10 each drop worker
list as workers
list as workers</lang>


Thread joining is automatic by default.
Thread joining is automatic by default.
Line 526: Line 522:
The number of concurrent jobs can be set by issuing that many echo '1''s at the begining to sem.
The number of concurrent jobs can be set by issuing that many echo '1''s at the begining to sem.


rm -f sem ; mkfifo sem
<lang bash>rm -f sem ; mkfifo sem


acquire() {
acquire() {
x='';while test -z "$x"; do read x; done;
x='';while test -z "$x"; do read x; done;
}
}


release() {
release() {
echo '1'
echo '1'
}
}


job() {
job() {
n=$1; echo "Job $n acquired Semaphore">&2 ; sleep 2; echo "Job $n released Semaphore">&2 ;
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 1 ; release > sem ) &
( acquire < sem ; job 2 ; release > sem ) &
( acquire < sem ; job 2 ; release > sem ) &
( acquire < sem ; job 3 ; release > sem ) &
( acquire < sem ; job 3 ; release > sem ) &


echo 'Initialize Jobs' >&2 ; echo '1' > sem
echo 'Initialize Jobs' >&2 ; echo '1' > sem</lang>


=={{header|Visual Basic .NET}}==
=={{header|Visual Basic .NET}}==
Line 550: Line 546:
This code shows using a local semaphore. Semaphores can also be named, in which case they will be shared system wide.
This code shows using a local semaphore. Semaphores can also be named, in which case they will be shared system wide.


Dim sem As New Semaphore(5, 5) 'Indicates that up to 5 resources can be aquired
<lang vbnet>Dim sem As New Semaphore(5, 5) 'Indicates that up to 5 resources can be aquired
sem.WaitOne() 'Blocks until a resouce can be aquired
sem.WaitOne() 'Blocks until a resouce can be aquired
Dim oldCount = sem.Release() 'Returns a resource to the pool
Dim oldCount = sem.Release() 'Returns a resource to the pool
'oldCount has the Semaphore's count before Release was called
'oldCount has the Semaphore's count before Release was called</lang>


{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->