Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 线程安全“;“漂亮的柜台”;(又名“施瓦兹计数器”)_C++_Multithreading_Initialization_C++17 - Fatal编程技术网

C++ 线程安全“;“漂亮的柜台”;(又名“施瓦兹计数器”)

C++ 线程安全“;“漂亮的柜台”;(又名“施瓦兹计数器”),c++,multithreading,initialization,c++17,C++,Multithreading,Initialization,C++17,“漂亮的计数器”(又名“施瓦兹计数器”)的名称 //Stream.cpp #包括“Stream.h” #包括//新位置 #包括//u存储 静态智能计数器;//零在加载时初始化 静态类型名称std::aligned_storage::type 溪流流对象的内存 溪流和溪流=重新解释浇铸(溪流); Stream::Stream() { //初始化事物 } 流::~流() { //清理 } StreamInitializer::StreamInitializer() { if(nifty_count

“漂亮的计数器”(又名“施瓦兹计数器”)的名称

//Stream.cpp
#包括“Stream.h”
#包括//新位置
#包括//u存储
静态智能计数器;//零在加载时初始化
静态类型名称std::aligned_storage::type
溪流流对象的内存
溪流和溪流=重新解释浇铸(溪流);
Stream::Stream()
{
//初始化事物
}
流::~流()
{
//清理
} 
StreamInitializer::StreamInitializer()
{
if(nifty_counter++==0)new(&stream)stream();//placement new
}
StreamInitializer::~StreamInitializer()
{
如果(--nifty_计数器==0)(&stream)->~stream();
}
看起来它是线程安全的。。。除了:

在主函数开始执行之前,所有具有静态存储持续时间的非局部变量都将作为程序启动的一部分进行初始化

到目前为止,一切顺利

(除非延期,见下文)

动态初始化是在
main
函数的第一条语句(对于静态)或线程的初始函数(对于线程局部变量)之前发生,还是延迟到之后发生,这是实现定义的

如果在
main
函数的第一条语句和
main
函数的第一条语句创建一个线程并且该线程访问
流之后,在第一个漂亮的计数器
静态
对象处的动态初始化延迟发生,如何保证在第二个线程中访问流对象之前,它已经在主线程中完全初始化

该代码是否包含竞争条件?如果是这样,您将如何修复它?使用读写器锁



编辑:使计数器原子化并不能解决问题。即使计数器是原子的,也不能保证构造函数在第二个线程上访问对象之前已在原始线程上完成。与保证线程安全的函数本地静态构造函数不同,通过placement
new

调用的构造函数不保证线程安全,而是使用原子计数器。漂亮的计数器在缓存中都是跺脚的,所以它的原子化也有最小的缺点。FWIW LIbSTDC++使用IOFFROW初始化器的原子计数器。使反原子不解决我指出的问题。不计算手动加载的动态库(它不遵循很多C++规则),尽管有这种允许,实现通常不会延迟初始化,而且不清楚是否可以一致地延迟初始化。实际上,这就足够了。原子计数器本身并不能解决这个问题,你需要像信号灯一样使用它。请看libstdc++实现。
// Stream.h
#ifndef STREAM_H
#define STREAM_H

struct Stream {
  Stream ();
  ~Stream ();
};
extern Stream& stream; // global stream object

static struct StreamInitializer {
  StreamInitializer ();
  ~StreamInitializer ();
} streamInitializer; // static initializer for every translation unit

#endif // STREAM_H
// Stream.cpp
#include "Stream.h"

#include <new>         // placement new
#include <type_traits> // aligned_storage

static int nifty_counter; // zero initialized at load time
static typename std::aligned_storage<sizeof (Stream), alignof (Stream)>::type
  stream_buf; // memory for the stream object
Stream& stream = reinterpret_cast<Stream&> (stream_buf);

Stream::Stream ()
{
  // initialize things
}
Stream::~Stream ()
{
  // clean-up
} 

StreamInitializer::StreamInitializer ()
{
  if (nifty_counter++ == 0) new (&stream) Stream (); // placement new
}
StreamInitializer::~StreamInitializer ()
{
  if (--nifty_counter == 0) (&stream)->~Stream ();
}