Using atomics with std::thread in c++11
Solution 1
You have to explicitly pass a ref to your thread. Using std::ref
will create a std::reference_wrapper
which is copyable and will carry the ref to your function.
thread t(setBool, std::ref(b));
Otherwise it will try to copy your atomic, which is uncopyable.
Solution 2
As bamboon explained, you have to wrap objects with std::ref
if you really want them to be passed by reference via std::thread
's variable-argument constructor. (The same applies to std::async
.) To avoid this counterintuitive behavior, you can use a lambda, which behaves precisely as you would expect. Just use this to create the thread:
thread t([&]{ setBool(b); });
With lambdas, there is no need for the ref/cref nonsense when you want to pass arguments by reference.
Solution 3
I just ran into this as well, I think you could also solve your problem by passing an address-to the atomic like so:
std::atomic<bool> b{false};
std::thread t(setBool, &b);
Where your function takes a pointer to the atomic:
void setBool(std::atomic<bool>* ab)
I'm not sure what the accepted practice is, I suppose you could pass a null pointer to the atomic this way but I'm not sure why you would want to.
Matt Kline
Embedded software engineer, typography & design enthusiast. BS in Computer Engineering and Computer Sciences from the University of Wisconsin-Madison Interests: Rust, hardware-software interface, performance-critical design, technical writing & presentation
Updated on June 04, 2022Comments
-
Matt Kline almost 2 years
I have a thread that I want to sit in a loop until I'm ready to exit the program, at which point I want it to break out of the loop and exit so I can call
std::thread::join
on it. In the days of c++03, I would just use a bool protected by a lock in order to tell the thread when to exit. This time I thought I would take advantage of the new atomics library (specificallystd::atomic_bool
), but I'm having trouble. Below is my test case:#include <atomic> #include <thread> #include <cstdio> using namespace std; void setBool(atomic_bool& ab) { ab = true; } int main() { atomic_bool b; b = false; thread t(setBool, b); t.join(); printf("Atomic bool value: %d\n", b.load()); return 0; }
The declaration of
thread t
spits out this monstrosity when I try to compile. The central part of the error seems to be:invalid initialization of non-const reference of type ‘std::atomic_bool&’ from an rvalue of type ‘std::atomic_bool’
Why can I not get a reference to an
atomic_bool
? What should I do instead?-
Matt Kline over 11 years@NicolBolas How so? Isn't locking a variable with a mutex before accessing it a standard way to share data between threads?
-
-
Matt Kline over 11 yearsWhy does it attempt a copy? Doesn't giving the variable name for a reference argument traditionally pass that variable by reference?
-
Stephan Dollberg over 11 years@slavik262 yes, that is true. The thread constructor does that, as you are invoking a function from which you don't know when it will execute, if you passed a reference, the reference might be invalid, thus it will copy your arguments to safely store them. If you explicitly use a ref-wrapper, it is your job to make sure that the object will outlive the thread.
-
Matt Kline over 11 yearsThanks! I'm well aware of lambdas (they're awesome) - I just wanted to minimize the amount of C++11 magic I was using for my test case to isolate the issue.
-
David Schwartz over 8 yearsMost of the time, you want to pass by value to a new thread. So that's the default.