std::atomic default value

std::atomic is a template that allows you to declare its contained value to be atomic: access to this value from different threads is well defined and does not lead to data races.

How to set values

std::atomic is not copyable and not movable.

Lets say we need an atomic value as a class member and want it to be set to a default value:

#include <atomic>

class Foo {
    std::atomic<bool> _online = true; // intuitive, but doesn't work
}

That doesn’t compile. Clang will tell us: "copying member subobject of type 'std::atomic_bool' (aka 'atomic<bool>') invokes deleted constructor."

Use the initialization constructor

Default values to atomic members can be assigned using an initializer list {} (braced initializer, or C++11 brace-init):

std::atomic<bool> _online{true};

For the complete API, refer to https://www.cplusplus.com/reference/atomic/atomic/

Aliases

And for those who want to improve readability a bit more, there are aliases we can use:

std::atomic_bool _online{true};

std::atomic_short
std::atomic_ushort
std::atomic_int
std::atomic_uint
std::atomic_long
std::atomic_ulong
std::atomic_llong
std::atomic_ullong
std::atomic_char8_t
std::atomic_char16_t
std::atomic_char32_t
std::atomic_wchar_t
std::atomic_int8_t
std::atomic_uint8_t
std::atomic_int16_t
std::atomic_uint16_t
std::atomic_int32_t
std::atomic_uint32_t
std::atomic_int64_t
std::atomic_uint64_t
std::atomic_int_least8_t
std::atomic_uint_least8_t
std::atomic_int_least16_t
std::atomic_uint_least16_t
std::atomic_int_least32_t
std::atomic_uint_least32_t
std::atomic_int_least64_t
std::atomic_uint_least64_t
std::atomic_int_fast8_t
std::atomic_uint_fast8_t
std::atomic_int_fast16_t
std::atomic_uint_fast16_t
std::atomic_int_fast32_t
std::atomic_uint_fast32_t
std::atomic_int_fast64_t
std::atomic_uint_fast64_t
std::atomic_intptr_t
std::atomic_uintptr_t
std::atomic_size_t
std::atomic_ptrdiff_t
std::atomic_intmax_t
std::atomic_uintmax_t

Tools

To detect data races you can use ThreadSanitizer, for example when you run your automated tests. It will tell you where to optimize your code.

clang++ -fsanitize=thread

And in cmake:

cmake -DCMAKE_C_FLAGS="-fsanitize=thread"

More about tsan here: https://clang.llvm.org/docs/ThreadSanitizer.html

async unit tests in C++

Sometimes we are in the situation where we need to test the result of a callback that is invoked on another thread and we don’t know when this will happen.

The problem? Our test already runs out of scope before the callback gets called. In order to test such a scenario we’ll need the following:

Lets assume we have a downloader that takes a while to download something, and (hopefully) reports true when it was successful:

class Downloader {
    asyncDownload(std::string url, std::function<void(bool)> callback) {
        std::thread downloadThread(download, std::move(callback));
        downloadThread.join();
    }

    download(std::string url, std::function<void(bool)> callback) {

        // perform download which takes a while
        ...
        if (everythingWentWell)
            callback(true);
    }
};

We could start writing our test case like this:

TEST(Downloader, testDownload) {
    auto callback = [](bool success) {
        EXPECT_TRUE(success);
    };
    Downloader downloader;
    downloader.download("http://foo.bar/interesting-file.jpg", std::move(callback));
}

This will leave us in a situation where the test case finishes while the Downloader is still downloading. What we need now is a way for the test case to wait until the callback is invoked, with a maximum timeout.

The way to go here is a promise with a 30s max timeout:

std::promise<void> waitGuard;
...
    EXPECT_EQ(boost::future_status::ready, waitGuard.get_future().wait_for(std::chrono::seconds(30)));

When the callback gets invoked, we inform the wait guard by setting a value. The test case now looks like this:

TEST(Downloader, testDownload) {
    std::promise<void> waitGuard;
    auto callback = [&](bool success) {
        // remember this gets called on the other thread
        EXPECT_TRUE(success);
        waitGuard.set_value();
    };
    Downloader downloader;
    downloader.download("http://foo.bar/interesting-file.jpg", std::move(callback));
    EXPECT_EQ(boost::future_status::ready, waitGuard.get_future().wait_for(std::chrono::seconds(30)));
}

Now, the test will wait until the download finishes and the callback gets called, but not more than 30s.