Multithreaded Programming
Introduction
Multithreaded applications can be built on neko. This tutorial contains three examples of how data can be shared between threads. In each example the main thread will start two other threads. One will send some data to the other, then they'll exit.
Creating and Destroying Threads
Threads are created using
neko.vm.Thread.create(doSomething)
where doSomething
is the function that the new thread will start running. The new thread will start immediately. When the thread exits doSomething
it will be destroyed.
Message Passing
In this example, the threads use the
neko.vm.Thread.sendMessage()
and neko.vm.Thread.readMessage()
functions. Note that these functions pass copies of simple types and pass objects by reference.
import neko.vm.Thread; import neko.Sys; import neko.Lib; class MessagePassing { static function main() { // create two thread, keep references Lib.println("Message Passing Example"); var t1 = Thread.create(sendMsgs); var t2 = Thread.create(getMsgs); // give thread1 ref to main thread and thread2 t1.sendMessage(Thread.current()); t1.sendMessage(t2); // give thread2 a ref to main thread t2.sendMessage(Thread.current()); // wait for them to finish Thread.readMessage(true); Thread.readMessage(true); Lib.println("done\n"); } // thread1 sends messages to thread2 static function sendMsgs() { // get ref to main and thread2 var main:Thread = Thread.readMessage(true); var t2:Thread = Thread.readMessage(true); for (ii in 0...5) { Lib.println("t1 sending: " + ii); t2.sendMessage(ii); Sys.sleep(.5); } main.sendMessage("thread1 done"); } // thread2 gets messages sent by thread1 static function getMsgs() { // get ref to main var main:Thread = Thread.readMessage(true); for (ii in 0...5) { Lib.println("t2 waiting for msg"); Lib.println("t2 got: " + Thread.readMessage(true)); } main.sendMessage("thread2 done"); } }
Shared Deque
In this example we will load data into a
Deque
in one thread and remove it in the other. The Deque
handles thread synchronization internally. Sharing data in this way with a List
or Array
is not recommended.
import neko.vm.Thread; import neko.vm.Deque; import neko.Lib; import neko.Sys; class SharedDeque { static function main() { // create deque for passing data var obj = new Deque<Int>(); // create two thread, keep references Lib.println("Shared Deque Example"); var t1 = Thread.create(sendMsgs); var t2 = Thread.create(getMsgs); // give each thread ref to main thread and deque t1.sendMessage(Thread.current()); t1.sendMessage(obj); t2.sendMessage(Thread.current()); t2.sendMessage(obj); // wait for them to finish Thread.readMessage(true); Thread.readMessage(true); Lib.println("done\n"); } // thread1 sends messages to thread2 static function sendMsgs() { // get ref to main and deque var main:Thread = Thread.readMessage(true); var obj:Deque<Int> = Thread.readMessage(true); for (ii in 0...5) { Lib.println("t1 pushing " + ii); obj.push(ii); Sys.sleep(.5); } main.sendMessage("thread1 done"); } // thread2 gets messages sent by thread1 static function getMsgs() { // get ref to main thread and deque var main:Thread = Thread.readMessage(true); var obj:Deque<Int> = Thread.readMessage(true); for (ii in 0...5) { Lib.println("t2 waiting for msg"); Lib.println("t2 got: " + obj.pop(true)); } main.sendMessage("thread2 done"); } }
Shared Object
In this example both threads share an object reference. The object synchronizes access to its data using a
neko.vm.Mutex
. This example is a bit different than the others in that the receiving thread doesn't remove the value and wait for the next one. Instead it just reads what's there.
import neko.vm.Thread; import neko.vm.Mutex; import neko.Lib; import neko.Sys; // an object to share between threads class Obj { public var m:Mutex; public var val(getVal,setVal):Int; public function new() { m = new Mutex(); val = 0; } private function getVal() { m.acquire(); var ret = val; m.release(); return ret; } private function setVal(v:Int) { m.acquire(); val = v; m.release(); return v; } } class UseMutex { static function main() { // create object to be shared var obj:Obj = new Obj(); // create two thread, keep references Lib.println("Shared Object Example"); var t1 = Thread.create(sendMsgs); var t2 = Thread.create(getMsgs); // give each thread ref to main thread and shared object t1.sendMessage(Thread.current()); t1.sendMessage(obj); t2.sendMessage(Thread.current()); t2.sendMessage(obj); // wait for them to finish Thread.readMessage(true); Thread.readMessage(true); Lib.println("done\n"); } // thread1 sends messages to thread2 static function sendMsgs() { // get ref to main and thread2 var main:Thread = Thread.readMessage(true); var obj:Obj = Thread.readMessage(true); for (ii in 0...5) { Lib.println("t1 setting" + ii); obj.val = ii; Sys.sleep(.5); } main.sendMessage("thread1 done"); } // thread2 gets messages sent by thread1 static function getMsgs() { var main:Thread = Thread.readMessage(true); var obj:Obj = Thread.readMessage(true); var ii = 0; while (ii != 4) { ii = obj.val; Lib.println("t2 got: " + ii); Sys.sleep(.3); } main.sendMessage("thread2 done"); } }
Results
Compile and run the examples with:
-neko messagepassing.n -main MessagePassing -cmd neko messagepassing.n --next -neko shareddeque.n -main SharedDeque -cmd neko shareddeque.n --next -neko usemutex.n -main UseMutex -cmd neko usemutex.n
The output should resemble:
Message Passing Example t2 waiting for msg t1 sending: 0 t2 got: 0 t2 waiting for msg t1 sending: 1 t2 got: 1 t2 waiting for msg t1 sending: 2 t2 got: 2 t2 waiting for msg t1 sending: 3 t2 got: 3 t2 waiting for msg t1 sending: 4 t2 got: 4 done Shared Deque Example t2 waiting for msg t1 pushing 0 t2 got: 0 t2 waiting for msg t1 pushing 1 t2 got: 1 t2 waiting for msg t1 pushing 2 t2 got: 2 t2 waiting for msg t1 pushing 3 t2 got: 3 t2 waiting for msg t1 pushing 4 t2 got: 4 done Shared Object Example t1 setting 0 t2 got: 0 t2 got: 0 t1 setting 1 t2 got: 1 t2 got: 1 t1 setting 2 t2 got: 2 t1 setting 3 t2 got: 3 t2 got: 3 t1 setting 4 t2 got: 4 done
"t1" refers to thread 1, the thread sending data. "t2" refers to thread 2, which is receiving data.
version #5754, modified 2009-04-14 02:30:49 by ianxm