std::thread参数的生命周期

7
当参数被传递给std::thread()时,新线程的本地存储中完全复制所有参数之前,生成新线程的原始线程是否等待?
简单示例:
void f()
{  
  int array[10];
  ........ //done something with array  
  std::thread th(someF, array); //assuming that someF accepts int[]  
  th.detach();  
}

我应该自动假设在f()结束之前所有数据都已经安全地复制了吗?假设f()不等待并全速前进,我所看到的一个场景是th正在尝试复制正在被销毁的array


2
你没有将一个数组传递给该线程,而是传递了指向第一个元素的指针。 - Casey
2个回答

4
是的。如果复制失败,它将在构造线程中抛出异常。
§30.3.1.2 线程构造器
template explicit thread(F&& f, Args&&... args);
要求:F和args中的每个Ti都应满足可移动构造要求。 INVOKE(DECAY_COPY(std :: forward(f)),DECAY_COPY(std :: forward(args))...)(20.8.2)应为有效表达式。
效果:构造一个类型为thread的对象。新的执行线程执行INVOKE(DECAY_COPY(std :: forward(f)),DECAY_COPY(std :: forward(args))...), 其中调用DECAY_COPY的调用在构造线程中被评估。此调用的任何返回值均被忽略。【注意:这意味着从f的副本调用未引发的任何异常将在构造线程中抛出,而不是新线程。-注】如果INVOKE(DECAY_COPY(std :: forward(f)),DECAY_COPY(std :: forward(args))...)的调用以未捕获的异常终止,则必须调用std :: terminate。
同步:构造函数的调用完成与f的副本的调用开始同步。

3

如果参数无法复制到新线程可用的存储空间,则会抛出异常。

来源于 http://en.cppreference.com/w/cpp/thread/thread/thread

在评估和复制/移动参数期间引发的任何异常都将在当前线程中引发,而不是在新线程中。


请注意,正确的术语不是“线程本地存储”。它们被复制到线程可访问的存储中。 “线程本地”存储是一个不同的、有些争议的概念。 - Pete Becker
我也注意到了这个奇怪的地方,但是参考页面上确切地写着:“创建一个新的 std::thread 对象并将其与执行线程相关联。首先构造函数将所有参数 args 复制/移动到线程本地存储中”。也许这是错的,或者还有更多内容?我会编辑答案以避免混淆。 - Phillip Kinkade
是的,“线程本地存储”这个提法是错误的。线程本地存储实际上是每个线程的静态存储(即,每个线程都有自己的线程本地数据副本,可以在线程中的任何函数中通过名称使用)。线程参数作为普通参数传递给被调用的函数。 - Pete Becker
请注意,该页面对“tread-local”的引用已更改为“thread-available”。 - Nate Kohl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接