All Source For Producer/Consumer Threads |
prodcons.bigforth |
\ $Id: prodcons.bigforth,v 1.1 2001/06/20 20:55:43 doug Exp $
\ http://www.bagley.org/~doug/shootout/
\ from Bernd Paysan
\ read NUM from last command line argument
0. argc @ 1- arg >number 2drop drop constant NUM
Variable count
Variable data
Variable produced
Variable consumed
\ note: no mutex is needed here. bigFORTH's tasker is cooperative
\ and switches tasks only with PAUSE.
: producer
up@ swap 2 $1000 dup NewTask pass
0 ?DO
BEGIN count @ 1 = WHILE pause REPEAT
1 count ! I data !
1 produced +!
LOOP wake ;
: consumer
up@ swap 2 $1000 dup NewTask pass
0 swap 0 ?DO
BEGIN count @ 0= WHILE pause REPEAT
0 count ! drop data @
1 consumed +!
LOOP drop wake ;
NUM producer
NUM consumer
\ There is no "main" task - to synchronize, each of the two new
\ threads get the task address of the starting task, and wake it
\ when they are done. The main task therefore has to stop twice
\ (and wait to be woken up)
stop stop
produced @ .
consumed @ 1 u.r cr
bye \ th-th-that's all folks!
|
prodcons.csharp |
// $Id: prodcons.csharp,v 1.0 2002/04/30 17:25:00 dada Exp $
// http://dada.perl.it/shootout/
// based on a sample from the Microsoft .NET SDK Documentation
using System;
using System.Threading;
using System.Collections;
class prodcons {
private int m_produced = 0;
private int m_consumed = 0;
private int m_count = 0;
private Queue m_smplQueue;
public prodcons(int count) {
m_count = count;
m_smplQueue = new Queue();
}
public void Producer() {
lock(m_smplQueue) {
while(m_produced < m_count) {
//Wait, if the queue is busy.
Monitor.Wait(m_smplQueue);
//Push one element.
m_smplQueue.Enqueue(m_produced);
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
m_produced++;
}
}
}
public void Consumer() {
while(m_consumed < m_count) {
lock(m_smplQueue) {
Monitor.Pulse(m_smplQueue);
while(Monitor.Wait(m_smplQueue,1000)) {
//Pop the first element.
m_smplQueue.Dequeue();
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
m_consumed++;
}
}
}
}
public void run() {
//Create the first thread.
Thread tProducer = new Thread(new ThreadStart(this.Producer));
//Create the second thread.
Thread tConsumer = new Thread(new ThreadStart(this.Consumer));
//Start threads.
tProducer.Start();
tConsumer.Start();
//wait to the end of the two threads
tProducer.Join();
tConsumer.Join();
//Print the number of the queue elements.
Console.WriteLine(this.m_produced.ToString() + " " + this.m_consumed.ToString());
}
}
class App {
public static int Main(String[] args) {
int n;
n = System.Convert.ToInt32(args[0]);
if(n < 1) n = 1;
new prodcons(n).run();
return 0;
}
}
|
prodcons.cygperl |
#!/usr/local/test/bin/perl
# $Id: prodcons.perl,v 1.2 2001/01/19 04:29:45 doug Exp $
# http://www.bagley.org/~doug/shootout/
use strict;
use Thread qw(cond_wait cond_signal);
my $count = 0;
my $data = 0;
my $produced = 0;
my $consumed = 0;
sub consumer {
my $n = shift;
while (1) {
lock($count);
cond_wait($count) while ($count == 0);
my $i = $data;
$count = 0;
$consumed++;
last if ($i == $n);
cond_signal($count);
}
}
sub producer {
my $n = shift;
for (my $i=1; $i<=$n; $i++) {
lock($count);
cond_wait($count) while ($count == 1);
$data = $i;
$count = 1;
$produced++;
cond_signal($count);
}
}
sub main {
my $n = ($ARGV[0] < 1) ? 1 : $ARGV[0];
my $p = Thread->new(\&producer, $n);
my $c = Thread->new(\&consumer, $n);
$p->join;
$c->join;
print "$produced $consumed\n";
}
&main();
|
prodcons.erlang |
%%% $Id: prodcons.erlang,v 1.0 2002/10/21 16:58:00 dada Exp $
%%% http://dada.perl.it/shootout
%%%
%%% contributed by James Hague
-module(prodcons).
-export([main/0, main/1, producer/2, consumer/1]).
main() -> main(['1']).
main([Arg]) ->
N = list_to_integer(atom_to_list(Arg)),
spawn(prodcons, producer, [self(), N]),
receive
{Produced, Consumed} ->
io:fwrite("~w ~w~n", [Produced, Consumed]),
halt(0)
end.
producer(From, N) ->
Result = producer_loop(spawn(prodcons, consumer, [0]), 0, N),
From ! Result.
producer_loop(Consumer, Produced, 0) ->
Consumer ! {self(), stop},
receive
Consumed -> {Produced, Consumed}
end;
producer_loop(Consumer, Produced, N) ->
Consumer ! {self(), N},
receive
ok -> producer_loop(Consumer, Produced + 1, N - 1)
end.
consumer(Consumed) ->
receive
{From, stop} ->
From ! Consumed;
{From, I} ->
From ! ok,
consumer(Consumed + 1)
end.
|
prodcons.gcc |
/* -*- mode: c -*-
* $Id: prodcons.gcc,v 1.3 2001/05/27 18:25:11 doug Exp $
* http://www.bagley.org/~doug/shootout/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t control;
void producer(unsigned int *arg);
void consumer(unsigned int *arg);
unsigned int count, data, consumed, produced;
int
main(int argc, char *argv[]) {
unsigned int n = ((argc == 2) ? atoi(argv[1]) : 1);
pthread_t t1, t2;
count = data = consumed = produced = 0;
if (pthread_mutex_init(&mutex, NULL)) {
perror("pthread_mutex_init");
exit(1);
}
if (pthread_cond_init(&control, NULL)) {
perror("pthread_cond_init");
exit(1);
}
if (pthread_create(&t1, (pthread_attr_t *)NULL,
(void * (*)(void *))producer, (void *)&n)) {
perror("pthread_create");
exit(1);
}
if (pthread_create(&t2, (pthread_attr_t *)NULL,
(void * (*)(void *))consumer, (void *)&n)) {
perror("pthread_create");
exit(1);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
fprintf(stdout, "%d %d\n", produced, consumed);
return(0);
}
void producer(unsigned int *arg) {
unsigned int i, n = *arg;
for (i=1; i<=n; i++) {
pthread_mutex_lock(&mutex);
while (count == 1) {
pthread_cond_wait(&control, &mutex);
}
data = i;
count = 1;
pthread_cond_signal(&control);
pthread_mutex_unlock(&mutex);
produced++;
}
}
void consumer(unsigned int *arg) {
unsigned int i = 0, n = *arg;
while (1) {
pthread_mutex_lock(&mutex);
while (count == 0) {
pthread_cond_wait(&control, &mutex);
}
i = data;
count = 0;
pthread_cond_signal(&control);
pthread_mutex_unlock(&mutex);
consumed++;
if (i == n) return;
}
}
|
prodcons.gforth |
\ $Id: prodcons.gforth,v 1.1 2001/06/20 20:55:44 doug Exp $
\ http://www.bagley.org/~doug/shootout/
\ from Bernd Paysan
require tasker.fs
\ read NUM from last command line argument
0. argc @ 1- arg >number 2drop drop constant NUM
Variable pcount
Variable data
Variable produced
Variable consumed
\ note: no mutex is needed here. bigFORTH's tasker is cooperative
\ and switches tasks only with PAUSE.
: producer
next-task swap 2 $1000 NewTask pass
0 ?DO
BEGIN pcount @ 1 = WHILE pause REPEAT
1 pcount ! I data !
1 produced +!
LOOP wake ;
: consumer
next-task swap 2 $1000 NewTask pass
0 swap 0 ?DO
BEGIN pcount @ 0= WHILE pause REPEAT
0 pcount ! drop data @
1 consumed +!
LOOP drop wake ;
NUM producer
NUM consumer
\ There is no "main" task - to synchronize, each of the two new
\ threads get the task address of the starting task, and wake it
\ when they are done. The main task therefore has to stop twice
\ (and wait to be woken up)
stop stop
produced @ .
consumed @ 1 u.r cr
bye \ th-th-that's all folks!
|
prodcons.ghc |
-- $Id: prodcons.ghc,v 1.1 2001/02/28 01:08:27 doug Exp $
-- http://www.bagley.org/~doug/shootout/
-- from Josef Svenningsson
module Main where
import CVar
import MVar
import Concurrent
import Exception
import IOExts
import System
producer :: Int -> IORef Int -> CVar Int -> IO ()
producer n p ch = sequence_ (map send [1..n])
where send i = do writeCVar ch i
prod <- readIORef p
writeIORef p (prod+1)
consumer :: Int -> IORef Int -> CVar Int -> IO ()
consumer n c ch = cons 1
where cons i | n <= i = return ()
cons i
= do i <- readCVar ch
con <- readIORef c
writeIORef c (con+1)
cons i
myForkIO :: IO () -> IO (MVar ())
myForkIO io = do
mvar <- newEmptyMVar
forkIO (io `finally` putMVar mvar ())
return mvar
join :: MVar () -> IO ()
join mvar = readMVar mvar
main = do (a:_) <- getArgs
let n = read a
produced <- newIORef 0
consumed <- newIORef 0
channel <- newCVar
p <- myForkIO (producer n produced channel)
c <- myForkIO (consumer n consumed channel)
join p; join c
prod <- readIORef produced
cons <- readIORef consumed
putStrLn (show prod ++ " " ++ show cons)
|
prodcons.gnat |
-- $Id: prodcons.gnat,v 1.0 2003/06/11 12:10:00 dada Exp $
-- http://dada.perl.it/shootout/
-- Ada 95 code by C.C.
with Ada.Strings.Fixed, Ada.Command_Line, Text_IO;
procedure ProdCons is
type Data_Type is new Integer;
End_Of_Data : constant Data_Type := Data_Type'First;
protected Queue is
entry Put (Data : Data_Type);
entry Get (Data_Out : out Data_Type);
private
Count : Natural := 0;
Buffer : Data_Type;
end Queue;
protected body Queue is
entry Put (Data : Data_Type)
when Count = 0 is
begin
Buffer := Data;
Count := Count + 1;
end Put;
entry Get (Data_Out : out Data_Type)
when Count /= 0 is
begin
Data_Out := Buffer;
Count := Count - 1;
end Get;
end Queue;
Produced, Consumed : Natural := 0;
task type Producer_Task (N : Natural);
task type Consumer_Task (N : Natural);
task body Producer_Task is
begin
for Data_K in 1 .. Data_Type (N) loop
Queue.Put (Data => Data_K);
Produced := Produced + 1;
end loop;
Queue.Put (Data => End_Of_Data);
end Producer_Task;
task body Consumer_Task is
Data : Data_Type;
begin
loop
Queue.Get (Data_Out => Data);
exit when Data = End_Of_Data;
Consumed := Consumed + 1;
end loop;
end Consumer_Task;
function L_Trim (Source : String; Side : Ada.Strings.Trim_End :=
Ada.Strings.Left) return String renames Ada.Strings.Fixed.Trim;
N : Natural := 0;
begin
begin
N := Natural'Value (Ada.Command_Line.Argument (1));
exception
when Constraint_Error => null;
end;
declare
Producer : Producer_Task (N => N);
Consumer : Consumer_Task (N => N);
begin
null;
end;
Text_IO.Put_Line (L_Trim (Natural'Image (Produced)) &
Natural'Image (Consumed));
end ProdCons;
|
prodcons.guile |
#!/usr/local/bin/guile \
-e main -s
!#
;;; $Id: prodcons.guile,v 1.3 2001/06/29 23:12:37 doug Exp $
;;; http://www.bagley.org/~doug/shootout/
(use-modules (ice-9 threads))
(define mutex (make-mutex))
(define access (make-condition-variable))
(define count 0)
(define data 0)
(define produced 0)
(define consumed 0)
;; the consumer thread definition seems wrong
;; how does it ever stop/get joined?
(define (consumer n)
(let ((i 0))
(while #t
(lock-mutex mutex)
(while (= count 0)
(wait-condition-variable access mutex))
(set! i data)
(set! count 0)
(signal-condition-variable access)
(unlock-mutex mutex)
(set! consumed (+ consumed 1)))))
(define (producer n)
(do ((i 1 (+ i 1)))
((> i n))
(lock-mutex mutex)
(while (= count 1)
(wait-condition-variable access mutex))
(set! data i)
(set! count 1)
(signal-condition-variable access)
(unlock-mutex mutex)
(set! produced (+ produced 1))))
(define (main args)
(let ((n (or (and (= (length args) 2) (string->number (cadr args))) 1)))
(let ((c (make-thread (lambda () (consumer n)))))
(producer n)
(join-thread c)
(display produced) (display " ") (display consumed) (newline))))
|
prodcons.ici |
// $Id: prodcons.ici,v 1.0 2003/01/03 12:06:00 dada Exp $
// http://dada.perl.it/shootout
//
// contributed by Tim Long
static n = argv[1] ? int(argv[1]) : 1;
static count = 0;
static consumed = 0;
static produced = 0;
static data = 0;
static
producer()
{
for (i := 1; i <= n; ++i)
{
waitfor (count == 0; "access")
{
data = i;
count = 1;
wakeup("access");
}
++produced;
}
return 1;
}
static
consumer()
{
do
{
waitfor (count != 0; "access")
{
i = data;
count = 0;
wakeup("access");
}
++consumed;
} while (i != n);
return 1;
}
p := thread(producer);
c := thread(consumer);
waitfor (p.result; p)
;
waitfor (c.result; c)
;
printf("%d %d\n", produced, consumed);
|
prodcons.java |
// $Id: prodcons.java,v 1.1 2000/12/20 13:41:33 doug Exp $
// http://www.bagley.org/~doug/shootout/
// Producer-Consumer Example by Bill Lear
// Adapted from http://java.sun.com/docs/books/tutorial/essential/threads
public class prodcons {
private class CubbyHole {
private int m_contents;
private boolean m_available = false;
public synchronized int get() {
while (m_available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
m_available = false;
notifyAll();
return m_contents;
}
public synchronized void put(int value) {
while (m_available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
m_contents = value;
m_available = true;
notifyAll();
}
}
private class Producer extends Thread {
private CubbyHole m_cubbyhole;
private int m_count;
public Producer(CubbyHole c, int count) {
m_cubbyhole = c;
m_count = count;
}
public void run() {
for (int i = 0; i < m_count; i++) {
m_cubbyhole.put(i);
++m_produced;
}
}
}
private class Consumer extends Thread {
private CubbyHole m_cubbyhole;
private int m_count;
public Consumer(CubbyHole c, int count) {
m_cubbyhole = c;
m_count = count;
}
public void run() {
int value = 0;
for (int i = 0; i < m_count; i++) {
value = m_cubbyhole.get();
++m_consumed;
}
}
}
public void run() {
m_producer.start();
m_consumer.start();
try { m_producer.join(); } catch (InterruptedException e) { }
try { m_consumer.join(); } catch (InterruptedException e) { }
System.out.println(m_produced + " " + m_consumed);
}
public prodcons(int count) {
CubbyHole m_cubbyhole = new CubbyHole();
m_producer = new Producer(m_cubbyhole, count);
m_consumer = new Consumer(m_cubbyhole, count);
}
public static void main(String[] args) {
int count = 1;
try { count = Integer.parseInt(args[0]); } catch (Exception e) { }
new prodcons(count).run();
}
private Producer m_producer;
private Consumer m_consumer;
private int m_produced = 0;
private int m_consumed = 0;
}
|
prodcons.mingw32 |
/* -*- mode: c -*-
* $Id: prodcons.gcc,v 1.3 2001/05/27 18:25:11 doug Exp $
* http://www.bagley.org/~doug/shootout/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t control;
void producer(unsigned int *arg);
void consumer(unsigned int *arg);
unsigned int count, data, consumed, produced;
int
main(int argc, char *argv[]) {
unsigned int n = ((argc == 2) ? atoi(argv[1]) : 1);
pthread_t t1, t2;
count = data = consumed = produced = 0;
if (pthread_mutex_init(&mutex, NULL)) {
perror("pthread_mutex_init");
exit(1);
}
if (pthread_cond_init(&control, NULL)) {
perror("pthread_cond_init");
exit(1);
}
if (pthread_create(&t1, (pthread_attr_t *)NULL,
(void * (*)(void *))producer, (void *)&n)) {
perror("pthread_create");
exit(1);
}
if (pthread_create(&t2, (pthread_attr_t *)NULL,
(void * (*)(void *))consumer, (void *)&n)) {
perror("pthread_create");
exit(1);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
fprintf(stdout, "%d %d\n", produced, consumed);
return(0);
}
void producer(unsigned int *arg) {
unsigned int i, n = *arg;
for (i=1; i<=n; i++) {
pthread_mutex_lock(&mutex);
while (count == 1) {
pthread_cond_wait(&control, &mutex);
}
data = i;
count = 1;
pthread_cond_signal(&control);
pthread_mutex_unlock(&mutex);
produced++;
}
}
void consumer(unsigned int *arg) {
unsigned int i = 0, n = *arg;
while (1) {
pthread_mutex_lock(&mutex);
while (count == 0) {
pthread_cond_wait(&control, &mutex);
}
i = data;
count = 0;
pthread_cond_signal(&control);
pthread_mutex_unlock(&mutex);
consumed++;
if (i == n) return;
}
}
|
prodcons.ocaml |
(*
* $Id: prodcons.ocaml,v 1.6 2001/07/28 21:52:59 doug Exp $
* http://www.bagley.org/~doug/shootout/
*
* ocamlopt -thread unix.cmxa threads.cmxa prodcons.ml -o prodcons
* or
* ocamlc -thread unix.cma threads.cma prodcons.ml -o prodcons
*)
let count = ref 0
let data = ref 0
let produced = ref 0
let consumed = ref 0
let m = Mutex.create ()
let c = Condition.create ()
let producer n =
for i = 1 to n do
Mutex.lock m;
while !count = 1 do Condition.wait c m done;
data := i;
incr count;
Condition.signal c;
Mutex.unlock m;
incr produced
done
let consumer n =
let i = ref 0 in
while !i <> n do
Mutex.lock m;
while !count = 0 do Condition.wait c m done;
i := !data;
decr count;
Condition.signal c;
Mutex.unlock m;
incr consumed
done
let n = if Array.length Sys.argv > 1 then int_of_string Sys.argv.(1) else 1
let p = Thread.create producer n and c = Thread.create consumer n;;
Thread.join p; Thread.join c;
Printf.printf "%d %d\n" !produced !consumed
|
prodcons.ocamlb |
(*
* $Id: prodcons.ocaml,v 1.6 2001/07/28 21:52:59 doug Exp $
* http://www.bagley.org/~doug/shootout/
*
* ocamlopt -thread unix.cmxa threads.cmxa prodcons.ml -o prodcons
* or
* ocamlc -thread unix.cma threads.cma prodcons.ml -o prodcons
*)
let count = ref 0
let data = ref 0
let produced = ref 0
let consumed = ref 0
let m = Mutex.create ()
let c = Condition.create ()
let producer n =
for i = 1 to n do
Mutex.lock m;
while !count = 1 do Condition.wait c m done;
data := i;
incr count;
Condition.signal c;
Mutex.unlock m;
incr produced
done
let consumer n =
let i = ref 0 in
while !i <> n do
Mutex.lock m;
while !count = 0 do Condition.wait c m done;
i := !data;
decr count;
Condition.signal c;
Mutex.unlock m;
incr consumed
done
let n = if Array.length Sys.argv > 1 then int_of_string Sys.argv.(1) else 1
let p = Thread.create producer n and c = Thread.create consumer n;;
Thread.join p; Thread.join c;
Printf.printf "%d %d\n" !produced !consumed
|
prodcons.oz |
%%% $Id: prodcons.oz,v 1.0 2002/11/05 12:23:00 dada Exp $
%%% http://dada.perl.it/shootout/
%%%
%%% contributed by Isaac Gouy
%% Section 11.5 of the Oz Tutorial provides these
%% implementations of Event and UnitBufferM and states:
%% in Oz, it is very rare to write programs in the
%% (traditional) monitor style shown above. In general
%% it is very awkward.
%%
%% There's an extensive treatment of Oz concurrency in
%% the book 'Concepts, Techniques, and Models of Computer
%% Programming' - find it online with google.
%%
%% Usage: start from command line with
%% ozc -x prodcons.oz -o prodcons.oz.exe
%% prodcons.oz.exe 100000
functor
import System Application
define
Produced
Consumed
class Event from BaseObject
prop locking
attr f r
meth init
X in f <- X r <- X
end
meth put(I)
X in lock @r=I|X r<-X end
end
meth get(?I)
X in lock @f=I|X f<-X end {Wait I}
end
meth wait
{self get(_)}
end
meth notify
{self put(unit)}
end
end
class UnitBufferM
attr item empty psignal csignal
prop locking
meth init
empty <- true
psignal <- {New Event init}
csignal <- {New Event init}
end
meth put(I)
X in
lock
if @empty then
item <- I
empty <- false
X = yes
{@csignal notify}
else X = no end
end
if X == no then
{@psignal wait}
{self put(I)}
end
end
meth get(I)
X in
lock
if {Not @empty} then
I = @item
empty <- true
{@psignal notify}
X = yes
else X = no end
end
if X == no then
{@csignal wait}
{self get(I)}
end
end
end
proc {Producer N I B}
if N > 0 then
{B put(I)}
%% {System.showInfo 'Produced '#I} %% just to check synchronization
{Producer N-1 I+1 B}
else Produced = {NewCell I} end
end
proc {Consumer N I B}
if N > 0 then
{B get(I)}
%% {System.showInfo 'Consumed '#I} %% just to check synchronization
{Consumer N-1 I+1 B}
else Consumed = {NewCell I} end
end
in
local Args N UB in
[Args] = {Application.getArgs plain}
N = {String.toInt Args}
UB = {New UnitBufferM init}
thread {Producer N 0 UB} end
thread {Consumer N 0 UB} end
%% Oz is a dataflow language.
%% The main thread will wait until logic variables
%% Produced and Consumed have been given values
{System.showInfo {Access Produced}#' '#{Access Consumed}}
end
{Application.exit 0}
end
|
prodcons.perl |
#!/usr/local/test/bin/perl
# $Id: prodcons.perl,v 1.2 2001/01/19 04:29:45 doug Exp $
# http://www.bagley.org/~doug/shootout/
use strict;
use Thread qw(cond_wait cond_signal);
my $count = 0;
my $data = 0;
my $produced = 0;
my $consumed = 0;
sub consumer {
my $n = shift;
while (1) {
lock($count);
cond_wait($count) while ($count == 0);
my $i = $data;
$count = 0;
$consumed++;
last if ($i == $n);
cond_signal($count);
}
}
sub producer {
my $n = shift;
for (my $i=1; $i<=$n; $i++) {
lock($count);
cond_wait($count) while ($count == 1);
$data = $i;
$count = 1;
$produced++;
cond_signal($count);
}
}
sub main {
my $n = ($ARGV[0] < 1) ? 1 : $ARGV[0];
my $p = Thread->new(\&producer, $n);
my $c = Thread->new(\&consumer, $n);
$p->join;
$c->join;
print "$produced $consumed\n";
}
&main();
|
prodcons.pike |
#!/usr/local/bin/pike// -*- mode: pike -*-
// $Id: prodcons.pike,v 1.3 2000/12/20 05:03:58 doug Exp $
// http://www.bagley.org/~doug/shootout/
inherit Thread.Condition: access;
inherit Thread.Mutex: mutex;
int data, consumed, produced, count;
void producer(int n) {
for (int i=1; i<=n; i++) {
object mtx = mutex::lock();
while (count != 0) access::wait(mtx);
data = i;
count += 1;
destruct(mtx);
access::signal();
produced += 1;
}
}
void consumer(int n) {
while (1) {
object mtx = mutex::lock();
while (count == 0) access::wait(mtx);
int i = data;
count -= 1;
access::signal();
destruct(mtx);
consumed += 1;
if (i == n) break;
}
}
void main(int argc, array(string) argv) {
int n = (int)argv[-1];
if (n < 1) n = 1;
data = consumed = produced = count = 0;
thread_create(producer, n);
consumer(n);
write("%d %d\n", produced, consumed);
}
|
prodcons.pliant |
# $Id: prodcons.pliant,v 1.0 2002/02/25 11:58:00 dada Exp $
# http://dada.perl.it/shootout/
module "/pliant/language/context.pli"
gvar Sem s
gvar Int count := 0
gvar Int data := 0
gvar Int produced := 0
gvar Int consumed := 0
gvar Int done := 0
function consumer n
arg Int n
var Int i
part forever
part consumer_wait
if(count = 0)
restart consumer_wait
leave consumer_wait
i := data
count := 0
# console "consuming " i eol
consumed := consumed + 1
if (i = n)
leave forever
restart forever
function producer n
arg Int n
for (var Int i) 1 n
part producer_wait
if(count = 1)
restart producer_wait
leave producer_wait
data := i
count := 1
# console "producing " i eol
produced := produced + 1
done := 1
gvar Str s_n := cast ((pliant_script_args translate Address 1) map CStr) Str
if (s_n parse (gvar Int n))
thread
# console "starting producer thread..." eol
share produced
share data
share count
share s
share done
producer n
thread
# console "starting consumer thread..." eol
share consumed
share data
share count
share s
consumer n
part wait_done
if (done = 1)
leave wait_done
restart wait_done
console produced " " consumed eol
s release
else
console "usage: prodcons.pliant <number>" eol
|
prodcons.poplisp |
;;; -*- mode: lisp -*-
;;; $Id: prodcons.cmucl,v 1.1 2001/04/26 03:53:05 doug Exp $
;;; http://www.bagley.org/~doug/shootout/
;;; From Jochen Schmidt
(defparameter *counter* 0)
(defparameter *produced* 0)
(defparameter *consumed* 0)
(defparameter *data* 0)
(defparameter *mutex* (mp:make-lock "Big Lock"))
(defun producer (n)
(declare (optimize (speed 3) (safety 0))
(fixnum n))
(loop :for i :of-type fixnum :from 1 :to n
:do
(mp:process-wait "Producer is waiting on Consumer" #'(lambda () (= *counter* 0)))
(mp:with-lock-held (*mutex*)
(setf *data* i
*counter* 1))
(incf *produced*)))
(defun consumer (n)
(declare (optimize (speed 3) (safety 0))
(fixnum n))
(let ((i 0))
(declare (fixnum i))
(loop
(mp:process-wait "Consumer is waiting on Producer" #'(lambda () (= *counter* 1)))
(mp:with-lock-held (*mutex*)
(setf i *data*
*counter* 0))
(incf *consumed*)
(when (= i n)
(return)))))
(let ((n (parse-integer (or (car pop11::poparglist) "1"))))
(declare (optimize (speed 3) (safety 0))
(fixnum n))
(setf *counter* 0
*produced* 0
*consumed* 0
*data* 0)
(let ((producer (mp:make-process #'(lambda () (funcall #'producer n)) :name "Producer"))
(consumer (mp:make-process #'(lambda () (funcall #'consumer n)) :name "Consumer")))
(mp:process-wait "Wait on Producer" #'(lambda () (eq (mp:process-state producer) :killed)))
(mp:process-wait "Wait on Consumer" #'(lambda () (eq (mp:process-state consumer) :killed)))
(format t "~A ~A~%" *produced* *consumed*))
|
prodcons.python |
#!/usr/local/bin/python
# $Id: prodcons.python,v 1.1 2000/12/20 04:33:20 doug Exp $
# http://www.bagley.org/~doug/shootout/
import sys
from threading import *
access = Condition()
count = 0
consumed = 0
produced = 0
data = 0
def consumer(n):
global count, data, consumed
while 1:
access.acquire()
while count == 0:
access.wait()
i = data
count = 0
access.notify()
access.release()
consumed += 1
if i == n:
break
def producer(n):
global count, data, produced
for i in xrange(1,n+1):
access.acquire()
while count == 1:
access.wait()
data = i
count = 1
access.notify()
access.release()
produced += 1
def main(n):
t1 = Thread(target=producer, args=(n,))
t2 = Thread(target=consumer, args=(n,))
t1.start()
t2.start()
t1.join()
t2.join()
print produced, consumed
main(int(sys.argv[1]))
|
prodcons.ruby |
#!/usr/local/bin/ruby
# -*- mode: ruby -*-
# $Id: prodcons.ruby,v 1.2 2000/12/20 04:33:20 doug Exp $
# http://www.bagley.org/~doug/shootout/
require 'thread'
def main(n)
mutex = Mutex.new
access = ConditionVariable.new
count = data = consumed = produced = 0
consumer = Thread.new do
i = 0
loop do
mutex.synchronize {
while count == 0 do access.wait(mutex) end
i = data
count = 0
access.signal
}
consumed += 1
if i == n then break end
end
end
producer = Thread.new do
for i in 1 .. n do
mutex.synchronize {
while count == 1 do access.wait(mutex) end
data = i
count = 1
access.signal
}
produced += 1
end
end
producer.join
consumer.join
puts "#{produced} #{consumed}"
end
main(Integer(ARGV.shift || 1))
|
prodcons.smlnj |
(* -*- mode: sml -*-
* $Id: prodcons.smlnj,v 1.1 2001/09/01 01:40:21 doug Exp $
* http://www.bagley.org/~doug/shootout/
* from Matthias Blume
*)
(* producer-consumer threads in SML/NJ
* (concurrency primitives re-implemented "by hand" on top of call/cc
* using the code in John Reppy's book "Concurrent Programming in ML")
*
* (C) 2001 Lucent Technologies, Bell Labs
* written by Matthias Blume
*)
structure Queue :> sig
exception Empty
type tt = unit SMLofNJ.Cont.cont
type q
val new : unit -> q
val enqueue : q * tt -> unit
val dequeue : q -> tt
val empty : q -> bool
end = struct
exception Empty
type tt = unit SMLofNJ.Cont.cont
type q = tt list ref * tt list ref
fun new () : q = (ref [], ref [])
fun enqueue ((f as ref [], ref []) : q, x) = f := [x]
| enqueue ((_, b as ref xs), x) = b := x :: xs
fun dequeue ((f, b) : q) =
case !f of
[] => (case rev (!b) of
x :: xs => (f := xs; b := []; x)
| [] => raise Empty)
| x :: xs => (f := xs; x)
fun empty ((ref [], ref []) : q) = true
| empty _ = false
end
structure Mutex :> sig
val yield : unit -> unit
val fork : (unit -> unit) -> unit
val exit : unit -> 'a
type mutex
type condition
val mutex : unit -> mutex
val lock : mutex -> unit
val unlock : mutex -> unit
val condition : mutex -> condition
val wait : condition -> unit
val signal : condition -> unit
val run : (unit -> unit) * Time.time -> unit
end = struct
local
structure C = SMLofNJ.Cont
structure Q = Queue
type tt = unit C.cont
(* We take the easy way out: Simply drop signals that
* arrive during an atomic section on the floor. This is
* enough for our purpose and simplifies the coding... *)
val atomicState = ref false
fun atomicBegin () = atomicState := true
fun atomicEnd () = atomicState := false
val readyQ : Q.q = Q.new ()
fun dispatch () = C.throw (Q.dequeue readyQ) ()
fun sigH (_: Signals.signal, _: int, k: tt) =
if !atomicState then k
else (Q.enqueue (readyQ, k); Q.dequeue readyQ)
in
fun yield () =
(atomicBegin ();
C.callcc (fn k => (Q.enqueue (readyQ, k); dispatch ()));
atomicEnd ())
fun exit () = (atomicBegin (); dispatch ())
fun fork f = let
val k = C.isolate (fn () => (atomicEnd ();
f () handle _ => ();
exit ()))
in
atomicBegin ();
Q.enqueue (readyQ, k);
atomicEnd ()
end
datatype mutex = Mutex of { locked : bool ref, blocked : Q.q }
fun mutex () = Mutex { locked = ref false, blocked = Q.new () }
fun lock (Mutex { locked, blocked }) =
(atomicBegin ();
if !locked then
C.callcc (fn k => (Q.enqueue (blocked, k);
dispatch ()))
else locked := true;
atomicEnd ())
fun unlock (Mutex { locked, blocked }) =
(atomicBegin ();
if Q.empty blocked then locked := false
else C.callcc (fn k => (Q.enqueue (readyQ, k);
C.throw (Q.dequeue blocked) ()));
atomicEnd ())
datatype condition = Cond of { mutex : mutex, waiting : Q.q }
fun condition m = Cond { mutex = m, waiting = Q.new () }
fun wait (Cond { mutex = m as Mutex { locked, blocked }, waiting }) =
(atomicBegin ();
C.callcc (fn k =>
(Q.enqueue (waiting, k);
if Q.empty blocked then (locked := false;
dispatch ())
else C.throw (Q.dequeue blocked) ()));
if !locked then
C.callcc (fn k => (Q.enqueue (blocked, k);
dispatch ()))
else locked := true;
atomicEnd ())
fun signal (Cond { waiting, ... }) =
(atomicBegin ();
if Q.empty waiting then ()
else Q.enqueue (readyQ, Q.dequeue waiting);
atomicEnd ())
fun run (f, t) = let
val oh = Signals.setHandler (Signals.sigALRM,
Signals.HANDLER sigH)
val _ = SMLofNJ.IntervalTimer.setIntTimer (SOME t)
fun reset () =
(ignore (Signals.setHandler (Signals.sigALRM, oh));
SMLofNJ.IntervalTimer.setIntTimer NONE)
in
(f () handle e => (reset (); raise e))
before reset ()
end
end
end
structure ProdCons : sig
val main : string * string list -> OS.Process.status
end = struct
fun doit n = let
val c_running = Mutex.mutex ()
val p_running = Mutex.mutex ()
val consumer's_turn = ref false
val data = ref 0
val produced = ref 0
val consumed = ref 0
val m = Mutex.mutex ()
val c = Mutex.condition m
fun producer () = let
fun wait () = if !consumer's_turn then wait (Mutex.wait c) else ()
fun loop i =
if i <= n then
let val _ = Mutex.lock m
val _ = wait ()
in
data := i;
consumer's_turn := true;
produced := !produced + 1;
Mutex.signal c;
Mutex.unlock m;
loop (i + 1)
end
else ()
in
loop 1 before Mutex.unlock p_running
end
fun consumer () = let
fun wait () = if !consumer's_turn then () else wait (Mutex.wait c)
fun loop () = let
val _ = Mutex.lock m
val _ = wait ()
val i = !data
in
consumer's_turn := false;
consumed := !consumed + 1;
Mutex.signal c;
Mutex.unlock m;
if i <> n then loop () else ()
end
in
loop () before Mutex.unlock c_running
end
val _ = Mutex.lock p_running
val _ = Mutex.lock c_running
val p = Mutex.fork producer
val c = Mutex.fork consumer
in
Mutex.lock p_running;
Mutex.lock c_running;
TextIO.output (TextIO.stdOut,
concat [Int.toString (!produced), " ",
Int.toString (!consumed), "\n"])
end
fun main (_, args) = let
val n = case args of [] => 1
| (x :: _) => getOpt (Int.fromString x, 1)
in
Mutex.run (fn () => doit n, Time.fromMilliseconds 1);
OS.Process.success
end
end
val _ = SMLofNJ.exportFn("prodcons", ProdCons.main);
|