6

Reading about cancellation and pthreads, it appears to me that best practice of a thread which loops infinitely is not to cancel the thread but to create a flag that will be checked by the thread.

This situation implies that at some point, a thread might attempt to read the flag while someone is writing to the flag. Is this thread safe? How would I go about making a simultaneous get_flag() and set_flag() safe?

wolf
  • 127
  • 7

5 Answers5

7

Given that multiple people commented that "in practice" it is OK to read a flag and nothing can really happen, I want to first point at a nice article on benign data races. Reading this article carefully should clarify that without synchronization primitives you can get funny behavior even when sharing a bool.

The somewhat obvious approach is to use a std::atomic<bool> to safely read and write the bool from different threads. If you can't use std::atomic<T> you'll need to find a suitable replacement, possibly a mutex or a platform specific primitive.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
3

As with all inter-thread shared state, either use a thread-safe class/library for the flag, or protect it yourself in a critical section guarded by a mutex, lock, or other appropriate synchronization primitive.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
3

While technically it might be undefined behavior to set a variable in one thread and read it in another without protection, this is one case (of very few) where it won't matter on most modern platforms.

If the child-thread is pre-empted in the middle of checking the variable, it might miss it (or not) in the current iteration, but will catch it in the next. If the main thread is pre-empted while setting the variable, the child thread might miss it (or, again, not) and detect it in the next iteration. In short, there's normally no need to worry.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    I recommend [this article](http://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong) on benign data races. – Dietmar Kühl Dec 23 '13 at 22:12
  • 1
    -1 The reading thread could have the variable cached and never notice that it's been updated. – John Kugelman Dec 24 '13 at 03:52
  • @JohnKugelman - yes, that could happen but, let's face it, that is extremely unlikely in anything except grossly-trivial threads that do next-to-nothing in their body, (and are usually written specifically to demonstrate that this can be made to happen, if you try really hard). – Martin James Dec 25 '13 at 23:16
  • @MartinJames That's a poor attitude to have when writing multithreaded code. Correctness must have a higher priority than brevity. Knowingly writing code that should work except in "extremely unlikely" circumstances is a disaster waiting to happen. Excising those obscure, rare failures caused by less-than-rigorous code is one of the most difficult things we as programmers do. – John Kugelman Dec 26 '13 at 04:09
  • @JohnKugelman - it's a shutdown boolean - the benefits of 'correctness' are barely applicable - the thing is shutting down anyway. – Martin James Dec 26 '13 at 11:39
1

The pthreads standard makes modifying a value in one thread while it is, or might be, modified in another thread undefined behavior. In practice, if you use a volatile bool, it will work on every platform you are likely to encounter. If you want to be strictly correct, you can either use a mutex to protect the flag, use atomic operations, or use memory barriers.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

If the flag has just two states (binary) then the solution is very simple - use a volatile variable either bool or int.

Setting an int variable should be flag = 1 OR flag = 0 and not ++flag or flag++

The flag must be volatile so it doesn't reside in a register after it's being used (read/write).

Syntax is:

volatile int flag; or volatile bool flag;

egur
  • 7,830
  • 2
  • 27
  • 47