Jump to content

Metered concurrency: Difference between revisions

m
Fixed lang tags.
(omit m4)
m (Fixed lang tags.)
Line 6:
 
The interface for the counting semaphore is defined in an Ada package specification:
<lang ada> 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;</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.
<lang ada> 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;</lang>
We now need a set of tasks to properly call an instance of ''Counting_Semaphore''.
<lang ada> 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;</lang>
 
=={{header|ALGOL 68}}==
<lang algol68>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 )
)</lang>
)
Output:
<lang algol68>Job 1 acquired Semaphore ... Job 1 releasing Semaphore
Job 3 acquired Semaphore ... Job 3 releasing Semaphore
Job 2 acquired Semaphore ... Job 2 releasing Semaphore</lang>
 
=={{header|C}}==
Line 259:
===Phobos with tools===
Using the scrapple.tools extension library for Phobos ..
<lang d>module metered;
module metered;
 
import tools.threads, tools.log, tools.time, tools.threadpool;
Line 280 ⟶ 279:
for (int i = 0; i < 10; ++i)
done.acquire;
}</lang>
}
</lang>
=={{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.
 
<lang e>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)
}</lang>
}
 
=={{header|Java}}==
Line 392 ⟶ 390:
Python threading module includes a semaphore implementation. This code show how to use it.
 
<lang python>import time
<pre>
import time
import threading
 
Line 429 ⟶ 426:
running = 0
for t in workers:
t.join()</lang>
</pre>
 
=={{header|Raven}}==
Counting semaphores are built in:
 
<lang raven># 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</lang>
 
Thread joining is automatic by default.
Line 526 ⟶ 522:
The number of concurrent jobs can be set by issuing that many echo '1''s at the begining to sem.
 
<lang bash>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</lang>
 
=={{header|Visual Basic .NET}}==
Line 550 ⟶ 546:
This code shows using a local semaphore. Semaphores can also be named, in which case they will be shared system wide.
 
<lang vbnet>Dim sem As New Semaphore(5, 5) 'Indicates that up to 5 resources can be aquired
sem.WaitOne() 'Blocks until a resouce can be aquired
Dim oldCount = sem.Release() 'Returns a resource to the pool
'oldCount has the Semaphore's count before Release was called</lang>
 
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have concurrency or background processes. -->
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.