Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

std::atomic passed as a const reference to a non-atomic type

Let’s say I have this application:

#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>

void do_something(const std::atomic<bool>& stop) {
    while (!stop) {
        std::cout << "Doing stuff..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main() {
    std::atomic<bool> stop { false };

    std::thread wait([&stop] { 
        std::this_thread::sleep_for(std::chrono::seconds(10));
        stop = true;
    });

    do_something(stop);

    wait.join();
}

This works as expected. The main thread loops until the wait thread sets stop. As far as I know, there’s no real issues with this application since it’s using an std::atomic<bool> for synchronization between the threads.

However, I can break the application by changing the signature of do_something to this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

void do_something(const bool& stop);

This still compiles without any warnings, but the loop in do_something never exits. Conceptually, I understand why this happens. do_something is accepting a const reference to a non-atomic value, so it would be reasonable to optimize the function to something like:

void do_something(const bool& stop) {
    if (!stop) {
        while(true) {
            std::cout << "Doing stuff..." << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}

What’s confusing to me is why the modified application compiles at all. I wouldn’t expect to be able to pass an std::atomic value into a function expecting a const reference to a non-atomic type. I haven’t looked at the standard, but I don’t see anything on cppreference that suggests this conversion is allowed.

Am I misunderstanding something here? Is this just some quirk of std::atomic that’s not obvious to me from the documentation?

>Solution :

This is because there is an implicit conversion when you call
do_something(const bool &stop)
while passing an std::atomic<bool>

It translates to:

do_something(static_cast<bool>(stop.operator bool()));

As you can see here : https://en.cppreference.com/w/cpp/atomic/atomic/operator_T

You actually tell the compiler to load the value once, right at the time of the call.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading