Data Race and VexOS Scheduler

Hello,

I have some questions about Vex threads, scheduler, and VexOS.
I have the following code:

// forward declaration
void count();
void myThreadCallback();

int global_counter = 0;

int main() {
  // two threads will read/write from same var
  thread myThread = thread(myThreadCallback);
  count();

  // this is needed else main will end before thread does
  myThread.join(); 
  // final result
  printf("%d\n", global_counter);
}

// thread will run this
void myThreadCallback() {
  for(int i = 0; i < 100000; i++){
    global_counter++;
  }
}

// called from main
void count(){
  for(int i = 0; i < 100000; i++){
    global_counter++;
  }

}

Running this code on a single-core VM (using std::thread) produces the correct increment 200,000 (as expected because the threads run concurrently, a single thread touching a variable at a time). 2+ core VM produces with wrong increment (as expected because the threads run at the same time leading to stale/bad variables).
The EXP produces the correct increment 200,000 all the time, from the above code on VEXcode IDE. However, it is noted here that a single-core scheduler can preempt before the thread was finishes i.e. produce a wrong increment answer.
I have the following questions:

  • Can the V5/EXP ever produce a data race? My tests point towards no but my threads had time to finish gracefully before the scheduler splice expired.
  • How is the scheduler implemented? I’m currently assuming preemptive but I’m not certain
  • What is the scheduler quantum?
  • Can Events in VEXcode produce a data race? Again, I couldn’t force a data race (between main() and event function reading the same variable)
  • Are Events an abstraction of threads or threads and interrupts?

Thank you for reading the post!

vexos does not use a pre-emptive scheduler, it’s a cooperative scheduler, that knowledge should answer most of your questions.

this thread would never cause a task switch, you would need to be using another API call or choosing to sleep/yield.

void myThreadCallback() {
  for(int i = 0; i < 100000; i++){
    global_counter++;
  }
}

spending too much time in a blocking loop like that will eventually cause an exception and the program will be stopped.

vex::thread is very different from std::thread, not really relevant to compare them.

5 Likes