链接 pthread 禁用 lock-free shared_ptr 实现

Linking pthread disables lock-free shared_ptr implementation

标题几乎传达了所有相关信息,但这里有一个最小的复制:

#include <atomic>
#include <cstdio>
#include <memory>

int main() {
    auto ptr = std::make_shared<int>(0);
    bool is_lockless = std::atomic_is_lock_free(&ptr);
    printf("shared_ptr is lockless: %d\n", is_lockless);
}

使用以下编译器选项编译它会产生一个 lock-free shared_ptr 实现:

g++ -std=c++11 -march=native main.cpp

虽然这不是:

g++ -std=c++11 -march=native -pthread main.cpp

GCC 版本:5.3.0(在 Linux 上,使用 libstdc++),在多台机器上测试,这些机器应该有必要的原子指令来完成这项工作。

有什么方法可以强制执行 lock-free(无论性能如何,我都需要 lock-free 版本)?

如果您在线程环境中使用 shared_ptr,您需要[某种类型的锁 - 它们可以实现为原子递增和递减,但可能有些地方 "bigger"需要锁定以确保没有比赛]。无锁版本仅在只有一个线程时有效。如果您不使用线程,请不要 link 和 -lpthread

我敢肯定有一些棘手的方法可以让编译器相信你并没有真正将线程用于你的共享指针,但如果你这样做的话你真的处于脆弱的区域 - 如果 shared_ptr 传递给线程?您现在也许可以保证这一点,但有人可能会无意或故意将其引入到在不同线程中运行的东西中,这一切都会中断。

有两件事:

  • 控制块(或等效物)中引用计数器的操作通常使用无锁原子实现 whenever possible不是std::atomic_is_lock_free告诉你的。

    • libstdc++的__shared_ptrtemplated on the lock policy,所以可以显式使用

      template<typename T>
      using shared_ptr_unsynchronized = std::__shared_ptr<T, __gnu_cxx::_S_single>;
      

      如果你知道自己在做什么。

  • std::atomic_is_lock_free 告诉您 shared_ptr 上的原子访问函数(std::atomic_{store, load, exchange, compare_exchange} 等)是否是无锁的。这些函数用于并发访问 same shared_ptr 对象,典型的实现将使用互斥锁。