View Subcategory

Create a multithreaded "Hello World"

Create a program which outputs the string "Hello World" to the console, multiple times, using separate threads or processes.

Example:

-Output-

Thread one says Hello World!
Thread two says Hello World!
Thread four says Hello World!
Thread three says Hello World!

-Notice that the threads can print in any order.
java
for (int i = 0; i < 4; i++) {
final int nr = i ;
new Thread(new Runnable() {
public void run() {
System.out.println("Thread " + new String[] { "one", "two", "three", "four" }[nr] + " says Hello World!");
}
}).start();
}
cpp
#include <iostream>
#include <string>

using namespace std;

int main(){
int pid;
string text[4]={"one","two","three","four"};
for (int i=0;i<4;i++){
pid=fork();
if (pid>0){
//cout << "Process("<<pid<<") - " << "Thread " << text[i] << " says Hello World!" << endl;
cout << "Thread " << text[i] << " says Hello World!" << endl;
exit(0);
}
}
return 0;
}
#include <iostream>
#include <string>

#include <omp.h>

int main() {
unsigned int const num_threads = 4;

std::string const names[] = { "one", "two", "three", "four" };

# pragma omp parallel num_threads(num_threads)
{
unsigned const id = omp_get_thread_num();
// Stream concatenation isn't thread-safe so we use a critical section.
# pragma omp critical
std::cout << "Thread " << names[id] << " says Hello World!" << std::endl;
}
}
erlang
-module(spam).
-export([spam/1]).

spam(N) when N<5 ->
spawn(fun() -> io:format("Hello World from thread ~p~n",[N]) end),
spam(N+1);
spam(_) -> void.
fsharp
let mappedString =
["Thread one says Hello World!";
"Thread two says Hello World!";
"Thread four says Hello World!";
"Thread three says Hello World!"]
|> Seq.map (fun str -> async { printfn "%s" str })

Async.RunSynchronously (Async.Parallel mappedString)
fantom
pool := ActorPool()
["one", "two", "three", "four"].each
{
a := Actor(pool) |Str name| { echo("Thread $name says Hello World!") }
a.send(it)
}

Create read/write lock on a shared resource.

Create multiple threads or processes who are either readers or writers. There should be more readers then writers.

(From Wikipedia):

Multiple readers can read the data in parallel but an exclusive lock is needed while writing the data. When a writer is writing the data, readers will be blocked until the writer is finished writing.

Example:

-Output-

Thread one says that the value is 8.
Thread three says that the value is 8.
Thread two is taking the lock.
Thread four tried to read the value, but could not.
Thread five tried to write to the value, but could not.
Thread two is changing the value to 9.
Thread two is releasing the lock.
Thread four says that the value is 9.
...

--Notice that when a needed resource is locked, a thread can set a timer and try again in the future, or wait to be notified that the resource is no longer locked.
java
public class ParallelPermutations {

Lock lock = new ReentrantLock();

Integer value = 8;

public static void main(String[] args) {
new ParallelPermutations(Arrays.asList(args));
}

public ParallelPermutations(List<String> words) {
for (int i = 0; i < 20; i++) {
final Integer cnt = i ;
if ( i % 3 == 0) {
new Thread(new Runnable() {
public void run() {
if ( ! lock.tryLock() ) {
System.out.println("Thread " + cnt + " tried to write the value, but could not.") ;
lock.lock();
}
value = (int) (Math.random() * 10);
System.out.println("Thread " + cnt + " is changing the value to " + value ) ;
lock.unlock();
System.out.println("Thread " + cnt + " is releasing the lock.") ;
}
}).start();
} else {
new Thread(new Runnable() {
public void run() {
if ( ! lock.tryLock() ) {
System.out.println("Thread " + cnt + " tried to read the value, but could not.") ;
lock.lock() ;
}
System.out.println("Thread " + cnt + " says that the value is " + value + ".") ;
lock.unlock();
}
}).start();
}
}
}
}
cpp
class reader
{
string name_;
public:
reader(const string& name) : name_(name) {}

void operator()() {
for (;;this_thread::sleep(posix_time::milliseconds(1)))
{
shared_lock<shared_mutex> lock(m, try_to_lock);
lock_guard<mutex> cout_lock(io_m);
cout << "Thread " << name_;
if (lock)
cout << " says that the value is " << shared_value << "." << endl;
else
cout << " tried to read the value, but could not." << endl;
}
}
};

class writer
{
string name_;
public:
writer(const string& name) : name_(name) {}
void operator()() {
for (;;this_thread::sleep(posix_time::milliseconds(1)))
{
unique_lock<shared_mutex> lock(m, try_to_lock);
lock_guard<mutex> cout_lock(io_m);
cout << "Thread " << name_;
if (lock)
{
cout << " is taking the lock." << endl;
shared_value = rand() % 10;
cout << "Thread " << name_ << " is changing the value to " << shared_value << endl;
cout << "Thread " << name_ << " is releasing the lock. " << endl;
}
else
cout << " tried to write to the value, but could not." << endl;
}
}
};

int main()
{
thread t1 = thread(reader("one"));
thread t2 = thread(reader("two"));
thread t3 = thread(reader("three"));
thread t4 = thread(writer("four"));
writer("five")();
}
fsharp
open System.Threading
let lock = new ReaderWriterLock()
let mutable value = 0
let lockTimeout = 1

let ReaderThread t =
let random = new System.Random()
for i in 0 .. 100 do
try
lock.AcquireReaderLock(lockTimeout)
try
printfn "Thread %i says that the value is %i" t value
finally
lock.ReleaseReaderLock()
with _ ->
printfn "Thread %i tried to read the value, but could not (timeout)." t
Thread.Sleep(random.Next(50))

let WriterThread t =
let random = new System.Random()
for i in 0 .. 100 do
try
lock.AcquireWriterLock(lockTimeout)
try
value <- random.Next(10)
printfn "Thread %i is changing the value to %i" t value
Thread.MemoryBarrier()
finally
lock.ReleaseWriterLock()
printfn "Thread %i is releasing the lock." t
with _ ->
printfn "Thread %i tried to write the value, but could not (timeout)." t
Thread.Sleep(random.Next(50))

[| 0 .. 20 |]
|> Array.iter (fun t ->
async {
if t % 3 = 0 then
WriterThread t
else
ReaderThread t
}
|> Async.Start
)

Separate user interaction and computation.

Allow your program to accept user interaction while conducting a long running computation.

Example:

Hello user! Please input a string to permute: (input thread)
abcdef
Passing on abcdef... (input thread)
Please input another string to permute: (input thread)
lol
Passing on lol... (input thread)
Done Work On abcdef! (worker thread)
["abcdef", "abcefd", ... ] (worker thread)
Please input another string to permute: (input thread)
EXIT
Quitting, I'll let my worker thread know... (input thread)
We'
re quitting! Alright! (worker thread)

--Notice, that this could be accomplished on the command line or within a GUI. The point is that computation and user interaction should take place on separate threads of control.
java
public class BackgroundComputation {

final protected Queue<Thread> threads = new ConcurrentLinkedQueue<Thread>() ;

public BackgroundComputation() {
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
try {
while (true) {
System.out.print("Enter string to permutate: ");
final String word = r.readLine();
if ("EXIT".equals(word) ) {
System.out.println("I'll let my worker thread know... (input thread)") ;
while (! threads.isEmpty())
threads.poll().stop(new ThreadDeath()) ;
break ;
}
Thread t = new Thread(new Runnable() {
public void run() {
try {
Set<String> permutationSet = new HashSet<String>();
for (int i = 0; i < word.length(); i++)
for (int j = i + 1; j <= word.length(); j++)
permutations("", word.substring(i, j), permutationSet);
System.out.println();
System.out.println("Received results: " + permutationSet);
System.out.print("Enter string to permutate: ");
} catch (ThreadDeath e) {
System.out.println("We're quitting! Alright!");
}
}

private void permutations(String prefix, String word, Set<String> permutations) {
int N = word.length();
if (N == 0)
permutations.add(prefix);
else
for (int i = 0; i < N; i++)
permutations(
prefix + word.charAt(i),
word.substring(0, i) + word.substring(i + 1, N),
permutations
);
}
});
t.start();
threads.add(t);
}
} catch (IOException ioe) {
System.out.println("IO error trying to read your name!");
System.exit(1);
}
}


public static void main(String[] args) {
new BackgroundComputation() ;
}
}
cpp
class bg_worker
{
mutex bg_mutex_;
condition_variable work_present_;
deque<string> work_queue_;

result calc_perm(string s) {
result perms = result(new list<string>());

// sleep to simulate lots of work...
this_thread::sleep(posix_time::seconds(3));
sort(s.begin(), s.end());
do {
perms->push_back(s);
} while (next_permutation(s.begin(), s.end()));
return perms;
}

public:
void submit_work(const string &s) {
lock_guard<mutex> lock(bg_mutex_);
work_queue_.push_back(s);
work_present_.notify_one();
}

void operator()() {
for (;;) {
unique_lock<mutex> lock(bg_mutex_);
while (work_queue_.empty())
work_present_.wait(lock);
string s = work_queue_.front();
work_queue_.pop_front();
lock.unlock();

if (s == "EXIT") {
lock_guard<mutex> cout_lock(cout_mutex);
cout << "We're quitting! Alright!" << endl;
break;
}

result perm = calc_perm(s);
lock_guard<mutex> cout_lock(cout_mutex);
cout << "Done Work On " << s << "!" << endl;
cout << perm << endl;
}
}
};

int main()
{
bg_worker worker;
thread bg_thr(boost::ref(worker));
bool done = false;

{
lock_guard<mutex> cout_lock(cout_mutex);
cout << "Hello user! Please input a string to permute:" << endl;
}

while (!done)
{
string input;
cin >> input;
{
lock_guard<mutex> cout_lock(cout_mutex);
if (input == "EXIT") {
cout << "Quitting, I'll let my worker thread know..." << endl;
done = true;
} else {
cout << "Passing on " << input << "..." << endl;
cout << "Please input another string to permute:" << endl;
}
}
worker.submit_work(input);
}

bg_thr.join();
}
fsharp
open System

/// Computes all permutations of an array
let rec permute = function
| [| |] -> [| [| |] |]
| a ->
a
|> Array.mapi (fun i ai ->
Array.sub a 0 i
|> Array.append (Array.sub a (i + 1) (a.Length - i - 1))
|> permute
|> Array.map (fun perm -> Array.append [| ai |] perm)
)
|> Array.concat

/// Computes all permutations of a string
let permuteString (s: string) =
s.ToCharArray()
|> permute
|> Array.map (fun p -> new String(p))


type PermuteMessage =
| PermuteString of string
| Cancel

let mailbox = new MailboxProcessor<PermuteMessage>(fun inbox ->
let rec loop() =
async {
let! msg = inbox.Receive()
match msg with
| PermuteString s ->
printfn "[Worker] Starting to work on %s" s
let p = permuteString s
printfn "[Worker] Done my work on %s" s
let firstElems =
if s.Length > 4 then
let first = p |> Seq.truncate 4 |> Seq.toArray
String.Join(", ", first) + ", ..."
else
String.Join(", ", p)
printfn "[Worker] Result is %s" firstElems
return! loop()
| Cancel ->
printfn "[Worker] Nuff done, I'm quitting!"
return ()
}
loop()
)

do
printfn "[Input] Setting up worker."
mailbox.Start()
let loop = ref true
while !loop do
printfn "[Input] Please enter a word, or EXIT to exit"
let s = Console.ReadLine()
match s with
| "EXIT" ->
printfn "[Input] Sending worker the cancellation notice."
mailbox.Post(Cancel)
loop := false
| _ ->
printfn "[Input] Sending task to the worker."
mailbox.Post(PermuteString s)
fantom
using concurrent
class Main
{
static Void main()
{
worker := Actor(ActorPool()) |Str s|
{
result := permute(s.chars).map { Str.fromChars(it) }
echo("Done Work On $s!")
echo(result)
}

Env.cur.out.writeChars("Hello, user! Please input a string to permute: ").flush
Env.cur.in.eachLine |line| {
echo("Passing on $line ...")
worker.send(line)
Env.cur.out.writeChars("Please input another string to permute: ").flush
}
}

static Obj[][] permute(Obj[] list, Obj[] prefix := [,])
{
list.isEmpty ?
[prefix] :
list.reduce([,]) |Obj[] r, Obj item, Int i -> Obj[]| {
r.addAll(permute(list.dup { removeAt(i) }, prefix.dup.add(item)))
}
}
}