Egor Tensin
Egor Tensin

Reputation: 608

Concurrent std::call_once calls

Could please someone explain me why both of the threads in this program (when compiled using the compilers shipped with Visual Studio 2012/2013) are blocked until both std::call_once calls are executed? Another Visual Studio bug (given that it behaves as expected when compiled with GCC)? Can someone please come up with a workaround? Imagine all the pain I've been through to narrow the problem down and please, be merciful.

#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>

namespace
{
    std::once_flag did_nothing;

    void do_nothing()
    { }

    void sleep_shorter_and_do_nothing_once()
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
        std::cout << "1\n";
        std::call_once(did_nothing, do_nothing);
        std::cout << "2\n";
    }

    std::once_flag sleeped_longer;

    void sleep_longer()
    {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    void sleep_longer_once()
    {
        std::cout << "3\n";
        std::call_once(sleeped_longer, sleep_longer);
        std::cout << "4\n";
    }
}

int main()
{
    std::thread t1(sleep_shorter_and_do_nothing_once);
    std::thread t2(sleep_longer_once);
    t1.join();
    t2.join();
    return 0;
}

To elaborate, it behaves as expected when compiled using GCC:

When compiled using the compilers shipped with Visual Studio 2012/2013, it behaves like this:

Clearly, it's a misbehavior. Or isn't it?

UPDATE: I cannot submit this as a Visual Studio bug, because my work account is for some reason "not authorized to submit feedback for this connection", whatever this means. I've got a reply from the Microsoft STL maintainer saying he'll hopefully investigate the issue at some time in the future.

Upvotes: 9

Views: 870

Answers (2)

Egor Tensin
Egor Tensin

Reputation: 608

I've got a reply from the STL maintainer at Microsoft saying the bug's fixed in Visual Studio 2015.

Upvotes: 2

Peixu Zhu
Peixu Zhu

Reputation: 2151

It prefers to be a misbehavior.
"The completion of an effective call to call_once on a once_flag object synchronizes with all subsequent calls to call_once on the same once_flag object." (N3242, 30.4.4.2-clause-3).

Upvotes: 0

Related Questions