# Threads The Bios implements preemptive multi-threading. The code is written in Minimacy, you are invited to read it. Once initialized, the Bios creates a thread which compiles your program and evaluates its “run” function. Your program may start another thread: fun main() = threadStart("myNewThread", lambda()= sleepMs(1000); echoTime "thread done" ); echoTime "main done";; >> 0.00: main done >> 1.00: thread done >> end of line This example shows how to start a new thread: - specify its name: this is usefull for monitoring purpose - provide a lambda function which will be evaluated by the thread In the example, the new thread sleeps for 1000 milliseconds and then, it echoes a message. In the output, we can see that the main thread echoes its message right away (timecode 0.00), and the new thread echoes its message after 1 second (timecode 1.00). Then the system detects that nothing can happen anymore, and it terminates (end of line). [[threadStart]] returns a type [[Thread]], and a thread itself may use [[thisThread]] to get its own type [[Thread]]. [[threadName]] retrieves the thread name. Now we can review this example: fun main() = let threadStart("myNewThread", lambda()= echoTime strFormat("starting thread '*'", threadName(thisThread)) ) -> th in onTimeout(1000, lambda()= threadPost(th, lambda()= echoTime strFormat("receive msg on thread '*'", threadName(thisThread)) ) );; >> 0.00: starting thread 'myNewThread' >> 1.01: receive msg on thread 'myNewThread' >> end of line In this example: - the new thread returned by threadStart is put into “th” - the main thread launches a timeout of 1000 milliseconds - when time is up, it posts a message to the new thread: a “message” is a lambda function which will be evaluated by the thread when it is available Internally each thread implements a queue of messages and evaluates them one after the other. When the queue is full, the sending thread is halted until the queue is reduced. # Synchronization Preemptive multithreading requires synchronization capabilities between threads. Minimacy provides Lock and Join. A Lock secures the evaluation of a lambda function. - You create a Lock with lockCreate. Only one thread at a time can use the lock. - Thread A and Thread B call lockSync with this lock and a lambda function - The system guarantees that one of the two threads will have to wait for the other to complete evaluation of the lambda function A Join is like a pipe: - thread A creates a join with joinCreate - then it may start a thread B, and call joinWait - the call to joinWait suspends thread A until thread B calls joinSend The Join allows an elegant “[[await]]” mechanism: fun await(asyncFun)= let joinCreate() -> join in ( threadStart("async", lambda()= call asyncFun(join)); joinWait(join) );; The lambda function asyncFun is called in a new thread with a new Join, and whatever it does, synchronous or asynchronous, at the end of the day it must call joinSend() to provide its result. We don’t care about the returned value of asyncFun. The following example illustrates how we make a synchronized version of an asynchronous calculation: fun main() = echoTime await(lambda(join)= onTimeout(1000, lambda()= joinSend(join, "done")) );; >> 1.0: done >> end of line