C++ 无等待或无锁初始化

C++ 无等待或无锁初始化,c++,C++,我一直在研究延迟初始化(比如说-全局变量,但它可以是任何类型的)。到目前为止,我想到的是 enum state { uninitialized, initializing, initialized }; state s; char memory[sizeof(T)]; T& initialize() { auto val = compare_and_swap(&s, state::uninitialized, state::initializing

我一直在研究延迟初始化(比如说-全局变量,但它可以是任何类型的)。到目前为止,我想到的是

enum state {
    uninitialized,
    initializing,
    initialized
};
state s;
char memory[sizeof(T)];
T& initialize() {
    auto val = compare_and_swap(&s, state::uninitialized, state::initializing);
    if (val == initialized)
        return *(T*)memory;
    if (val == initializing) {
        while(atomic_read(&s) != state::initialized);
        return *(T*)memory;
    }
    new (memory) T();
    atomic_write(&s, state::initialized);
    return *(T*)memory;
}
在已经初始化的情况下,它是无等待的。但是在一个线程初始化的情况下,我遇到了一个问题。完成初始化或等待初始化完成所需的步骤数与线程数不成正比。但是如果初始化线程暂停,其他线程都必须任意等待,直到它恢复。所以在一般情况下,它不是无锁的或无等待的


有可能创建无等待或无锁的延迟初始化吗?

我认为在一般情况下这两种方法都不可能。如果在调用main和创建线程之前,作为全局初始化的一部分执行此操作,那么您就有机会了。它如何可以是无等待或无锁的

如果您允许初始化失败并稍后重试,它可能是无锁的。 如果另一个线程有该项,则不能等待空闲


如果您关心这里的性能,那么您可以使用线程id散列到一个项目桶中,以尝试减少争用频率。

如果您愿意初始化多个对象,那么您可以通过只存储一个指针来生成无锁代码:

std::atomic<T *> p { nullptr };

T & get()
{
    T * q = p.load();
    if (!q)
    {
        T * r = new T;
        if (p.compare_exchange_strong(q, r))
        {
            return *r;
        }
        else
        {
            delete r;
            return *q;
        }
    }
    return *q;
}

这段代码甚至不是无锁的……它显然不是无锁的。这就是问题的根源。如果我有无锁惰性初始化,为什么我会问一个关于是否可能的问题;我被复杂的代码甩了-如果你只是想要一个锁定延迟初始化,你可以使用一个
静态
变量并完成它。代码还需要
alignas(alignof(T))
,如果
T
的析构函数有副作用,并且您没有合适的清理,则会导致未定义的行为:-(如果
T
construction抛出了一个异常,那么你的代码将是活锁。这就是我刚刚提出的方法。严格来说,这个算法不也是免等待的吗?@DeadMG:如果你想要无锁,你不能依赖任何一个线程。无锁的全部目的是,即使有任意数量的线程,你也可以取得进展我们无限期地停止了。我想知道是否有可能使用光纤或其他技术来“窃取”从另一个被阻塞的线程中完成了一半的初始化。@ DIALMG:在一般情况下不太可能。Fipe需要从用户代码中进行协作。我猜如果你考虑一个被外部资源阻塞的线程——比如说任意加载一个网页——那么它就不能恢复。所以你不可能恢复它。延迟初始化是任意的,因此它不能是无锁的。
delete p.exchange(nullptr);