std::call_once seems not to free the lock in case of an exception?

Viewed 88

According to the cppreference.com the std::call_once should work correctly with functions which might throw an exception. Having said that, testing the example represented there it results in an infinite waiting instead of joining all threads.

the example from the page above:

#include <iostream>
#include <thread>
#include <mutex>
 
std::once_flag flag1, flag2;
 
void simple_do_once()
{
    std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
 
void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n"; // this may appear more than once
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n"; // guaranteed once
}
 
void do_once(bool do_throw)
{
  try {
    std::call_once(flag2, may_throw_function, do_throw);
  }
  catch (...) {
  }
}
 
int main()
{
    std::thread st1(simple_do_once);
    std::thread st2(simple_do_once);
    std::thread st3(simple_do_once);
    std::thread st4(simple_do_once);
    st1.join();
    st2.join();
    st3.join();
    st4.join();
 
    std::thread t1(do_once, true);
    std::thread t2(do_once, true);
    std::thread t3(do_once, false);
    std::thread t4(do_once, true);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

In my case it results in the infinite waiting after the following output:

Simple example: called once
throw: call_once will retry

for all the following versions the result is the same.

clang++

clang version 10.0.0-4ubuntu1 
Target: x86_64-pc-linux-gnu
Thread model: posix

g++

g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
g++-10 (Ubuntu 10.2.0-5ubuntu1~20.04) 10.2.0

What does that mean?

0 Answers
Related