Concurrent computing

From Rosetta Code
Revision as of 23:42, 22 August 2008 by rosettacode>Mwn3d (Added to Basic learning cat)
Task
Concurrent computing
You are encouraged to solve this task according to the task description, using any language you may know.

Using either native language concurrency syntax or freely available libraries write a program to display the strings "Enjoy" "Rosetta" "Code", one string per line, in random order. Concurrency syntax must use threads, tasks, co-routines, or whatever concurrency is called in your language.


Ada

<ada>with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;

procedure Concurrent_Hello is

  task type Writer (Message : access String);
  task body Writer is
     Seed : Generator;
  begin
     Reset (Seed); -- This is time-dependent, see Reference Manual A.5.2
     delay Duration (Random (Seed));
     Put_Line (Message.all);
  end Writer;
 
  S1 : aliased String := "Enjoy";
  S2 : aliased String := "Rosetta";
  S3 : aliased String := "Code";
  T1 : Writer (S1'Access);
  T2 : Writer (S2'Access);
  T3 : Writer (S3'Access);

begin

  null;

end Concurrent_Hello;</ada>

Note that random generator object is local to each task. It cannot be accessed concurrently without mutual exclusion. In order to get different initial states of local generators Reset is called.

ALGOL 68

main:(
  PROC echo = (STRING string)VOID:
      printf(($gl$,string));
  PAR(
    echo("Enjoy"),
    echo("Rosetta"),
    echo("Code")
  )
)

D

Library: Tango

<d>import tango.core.Thread; import tango.io.Console; import tango.math.Random;

void main() {

   (new Thread( { Thread.sleep(Random.shared.next(1000) / 1000.0); Cout("Enjoy").newline; } )).start;
   (new Thread( { Thread.sleep(Random.shared.next(1000) / 1000.0); Cout("Rosetta").newline; } )).start;
   (new Thread( { Thread.sleep(Random.shared.next(1000) / 1000.0); Cout("Code").newline; } )).start;

}</d>

E

def base := timer.now()
for string in ["Enjoy", "Rosetta", "Code"] {
    timer <- whenPast(base + entropy.nextInt(1000), fn { println(string) })
}

Nondeterminism from preemptive concurrency rather than a random number generator:

def seedVat := <import:org.erights.e.elang.interp.seedVatAuthor>(<unsafe>)
for string in ["Enjoy", "Rosetta", "Code"] {
   seedVat <- (`
       fn string {
           println(string)
           currentVat <- orderlyShutdown("done")
       }
   `) <- get(0) <- (string)
}

Forth

Works with: gforth version 0.6.2

Many Forth implementations come with a simple cooperative task scheduler. Typically each task blocks on I/O or explicit use of the pause word. There is also a class of variables called "user" variables which contain task-specific data, such as the current base and stack pointers.

require tasker.fs
require random.fs

: task ( str len -- )
  64 NewTask 2 swap pass
  ( str len -- )
  10 0 do
    100 random ms
    pause 2dup cr type
  loop 2drop ;

: main
  s" Enjoy"   task
  s" Rosetta" task
  s" Code"    task
  begin pause single-tasking? until ;
main

Groovy

'Enjoy Rosetta Code'.tokenize().collect { w ->
    Thread.start {
        Thread.sleep(1000 * Math.random() as int)
        println w
    }
}.each { it.join() }

Haskell

Note how the map treats the list of processes just like any other data.

import Control.Monad
import Control.Concurrent

main = sequence $ map forkIO $ [process1, process2, process3] where
  process1 = putStrLn "Enjoy" 
  process2 = putStrLn "Rosetta"
  process3 = putStrLn "Code"


Java

<java>public class Threads{

  public static void main(String[] args){
     Thread enjoy = 
           new Thread(){
              //this overridden method counts once every second up to five
              public void run(){
                 System.out.println("Enjoy");
              }
           };
     Thread rose = 
           new Thread(){
              //this overridden method counts once every second up to five
              public void run(){
                 System.out.println("Rosetta");
              }
           };
     Thread code = 
           new Thread(){
              //this overridden method counts once every second up to five
              public void run(){
                 System.out.println("Code");
              }
           };
     //these will probably (but not definitely) run in the order they are called since the runnable code is so short
     enjoy.start(); //calling .run() will not run it in a new thread
     rose.start();
     code.start();
  }

}</java>

JavaScript

Works with: Firefox version 2.0

<javascript>var textbox = document.getElementsByTagName("textarea")[0]; setTimeout( function(){ textbox.value += "Enjoy\n"; }, Math.random() * 1000 ); setTimeout( function(){ textbox.value += "Rosetta\n"; }, Math.random() * 1000 ); setTimeout( function(){ textbox.value += "Code\n"; }, Math.random() * 1000 );</javascript>

Perl

<perl>use threads; use Time::HiRes qw(sleep);

$_->join for map {

   threads->create(sub {
       sleep rand;
       print shift, "\n";
   }, $_)

} qw(Enjoy Rosetta Code);</perl>

Python

Works with: Python version 2.5

<python>import threading import random

def echo(string):

   print string

threading.Timer(random.random(), echo, ("Enjoy",)).start() threading.Timer(random.random(), echo, ("Rosetta",)).start() threading.Timer(random.random(), echo, ("Code",)).start()</python>

Raven

[ 'Enjoy' 'Rosetta' 'Code' ] as $words

thread talker
    $words pop "%s\n"
    repeat dup print
        500 choose ms

talker as a
talker as b
talker as c

Rhope

Works with: Rhope version alpha 1
Main(0,0)
|:
    Print["Enjoy"]
    Print["Rosetta"]
    Print["Code"]
:|

In Rhope, expressions with no shared dependencies run in parallel by default.

Ruby

%w{Enjoy Rosetta Code}.map do |x|

   Thread.new do
       sleep rand
       puts x
   end

end.each do |t|

 t.join

end

Tcl

Assuming that "random" means that we really want the words to appear in random (rather then "undefined" or "arbitrary") order:

 after [expr int(1000*rand())] {puts "Enjoy"}
 after [expr int(1000*rand())] {puts "Rosetta"}
 after [expr int(1000*rand())] {puts "Code"}

will execute each line after a randomly chosen number (0...1000) of milliseconds.

A step towards "undefined" would be to use after idle, which is Tcl for "do this whenever you get around to it". Thus:

 after idle {puts "Enjoy"}
 after idle {puts "Rosetta"}
 after idle {puts "Code"}

(While no particular order is guaranteed by the Tcl spec, the currently existing interpreters would probably all execute these in the order in which they were added to the after queue).

UnixPipes

(echo "Enjoy" & echo "Rosetta"& echo "Code"&)