繁体   English   中英

为什么std :: call_once在连接和分离的线程中表现不同?

[英]Why std::call_once behave different in joined and detached threads?

我写了一个小测试项目,看看在执行callable时std :: call_once是否阻塞。 项目的输出允许假设call_once有2个行为:它在分离的线程上阻塞,而在join 阻塞 我强烈怀疑这不可能成立,但是我无法得出其他结论,请指导我做出正确的结论。

using namespace std;
once_flag f;
mutex cout_sync;

void my_pause() 
{
  volatile int x = 0;
  for(int i=0; i<2'000'000'000; ++i) { x++; }
}

void thr(int id) 
{
  auto start = chrono::system_clock::now();
  call_once(f, my_pause);
  auto end = chrono::system_clock::now();
  scoped_lock l{cout_sync};
  cout << "Thread " << id << " finished in " << (static_cast<chrono::duration<double>>(end-start)).count() << " sec" << endl;
}

int main() 
{
  vector<thread> threads;
  for(int i=0; i<4; i++)
  {
    threads.emplace_back(thr, i);
    threads.back().join();
  }      
  return 0;
}

输出:

Thread 0 finished in 4.05423 sec
Thread 1 finished in 0 sec
Thread 2 finished in 0 sec
Thread 3 finished in 0 sec

将线程更改为分离线程:

for(int i=0; i<4; i++)
{
  threads.emplace_back(thr, i);
  threads.back().detach();
}
this_thread::sleep_for(chrono::seconds(5));

输出:

Thread 0 finished in 4.08223 sec
Thread 1 finished in 4.08223 sec
Thread 3 finished in 4.08123 sec
Thread 2 finished in 4.08123 sec

Visual Studio 2017

实际上,这与以下事实有关:您在连接的版本中先加入线程,然后再开始下一个线程。

这些语义是由于call_once规范而触发

如果该调用引发异常,则将其传播到call_once的调用者,并且不会翻转该标志,以便尝试另一个调用(这种对call_once的调用称为异常)。

这意味着,如果call_once'd函数引发异常,则认为该异常不会被调用,并且对call_once的下一次调用将再次调用该函数。

这意味着整个call_once()受内部互斥量有效保护。 如果正在执行call_once-d函数,则必须阻止其他任何进入call_once()的线程,直到call_once-d函数返回为止。

您一次加入一个线程,因此直到第一个线程中的call_once返回之前,第二个线程才被调用。

您可以同时有效地启动所有四个分离的线程。 实际上,所有四个线程将大致一起输入call_once。

这些线程之一将最终执行被调用的函数。

其他线程将被阻塞,直到被调用函数返回或引发异常。

这实际上意味着所有线程都必须等待。

这与分离的线程无关。

如果将代码的第一个版本更改为先启动所有四个线程,然后再将它们全部加入,则将看到相同的行为。

不同是不一样的。

未分离的线程按顺序运行-代码等待直到一个线程完成,然后再启动下一个线程。 因此,第一个进入等待循环,而其他则没有。

分离的线程同时运行。 其中一个运行等待循环,其他运行直到等待循环结束。

更改非分离线程的代码以同时运行它们。 为此,请将联接移到创建线程的循环之外。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM