The main idea here is that we have 3 variables: "count1", "count2", and the cleverly named variable "wally". We expect at all times that wally = count1 + count2. This is initially true, since they are all initialized to zero.
When thread "racer1" increments count1, it also increments wally.
When thread "racer2" increments count2, it also increments wally.
We stir up trouble by running "racer1" on an timer (and to roll the dice more often, we run the timer at 10,000 Hz rather than the default 1000). The trouble is that both threads have a shared resource, namely "wally". And although incrementing it is a single C statement, the processor needs to read, increment, then store the variable, which are 3 operations. If an interrupt happens in the midst of these statements, we get a race and the program detects it (and once it gets 10 of them it stops).
#include "kyu.h" #include "thread.h" static volatile int wally = 0; static volatile int count1 = 0; static volatile int count2 = 0; void racer1 ( int xx ) { for ( ;; ) { thr_delay ( 1 ); count1++; wally++; } } void racer2 ( int xx ) { int races = 0; while ( races < 10 ) { wally++; count2++; if ( wally != count1 + count2 ) { printf ( "Race after %d / %d (%d)\n", count1, count2, wally ); wally = count1 + count2; races++; } } printf ( "Done\n" ); } void user_init ( int xx ) { timer_rate_set ( 10000 ); (void) thr_new ( "racer1", racer1, (void *) 0, 20, 0 ); (void) thr_new ( "racer2", racer2, (void *) 0, 30, 0 ); thr_show (); }Note the calls to thr_new(). The arguments are as follows:
In a real time system like Kyu, the scheduler is emphatically unfair. At any time, the most urgent ready thread runs, period, no questions asked. This is a bit of a shock to some people, but in a properly designed real time system, this is exactly as it should be. If the most urgent thread never blocks, that would probably be a design failure and indeed all other threads would get starved. More on this later.
Kyu / tom@mmto.org