0

I have a thread that is started and runs continuously upon launch of the program (I'm using pthreads). I need to send commands to the thread from the main thread. I can set a global variable, but that seems risky because what if the secondary thread and main thread try to access it simultaneously? I can wrap the variable in a mutex, but is that necessary? What if I just put in the main thread a button that executes code like this:

// main thread
if(!trigger_variable)
    trigger_variable=1;

Then, in the second thread I use this:

// other thread
if(trigger_variable){
    do_something();
    trigger_variable=0;
}

Would this be robust enough to avoid using a mutex?

Synthetix
  • 2,035
  • 3
  • 24
  • 30
  • Not really enough info. How is each thread triggered to check the condition? Are there any other threads involved? Are these the only place that reads/writes the variable? – kaylum Oct 31 '21 at 03:24
  • Do you want the worker thread to sleep while it is waiting for a command from the main thread? If so, you may want to read about the [producer/consumer problem](https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem) and also look into [pthread condition variables](https://stackoverflow.com/questions/20772476/when-to-use-pthread-condition-variables). – Andreas Wenzel Oct 31 '21 at 03:49
  • @kaylum There aren't any other threads involved. Just the main thread triggering a second thread. There wouldn't be any other reads/writes other than these two examples. – Synthetix Oct 31 '21 at 04:03
  • @Andreas The second thread is actually doing stuff all the time, so this isn't quite a producer/consumer situation (although other parts of my app behave that way). I just need to tell the thread to modify its behavior when triggered by the user. – Synthetix Oct 31 '21 at 04:14

2 Answers2

3

A trigger_variable can work as long as it's an atomic type; for regular/non-atomic types it would invoke undefined behavior, since you'd have two threads reading and writing the same memory without any synchronization.

However, setting a shared variable is not exactly "sending a command" so much as setting a piece of shared state, so I wouldn't call it "bulletproof" for this purpose. For example, if you wanted to send two commands in quick succession, it would be difficult to guarantee that both were received, since the second change to the variable might overwrite the first one before the child thread ever got a chance to see the first value.

If you want to be able to send commands properly (e.g. so that each command is received by the child thread, in the order the commands were sent) one relatively easy way to do it would be have the main thread create a pipe and give the data-reading-file-descriptor of the pipe to the child thread. Then the main thread can write() a byte on the data-writing-file-descriptor whenever it wants the child thread to do something, and the child thread can read() that byte and react appropriately.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Using a pipe is a great idea! Seems like that would be safer and also more portable, as it wouldn't require atomic data types only available in later C standards. – Synthetix Oct 31 '21 at 04:11
1

According to §5.1.2.4 ¶25 and ¶4 of the official ISO C11 standard, two different threads reading and writing to the same memory location using non-atomic operations in an unordered fashion causes undefined behavior.

However, if you use atomic types instead, or the atomic operations libary, then your plan should work.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39