正确的方法来创建没有锁的thread_safe shared_ptr?

时间:2016-10-03 14:17:47

标签: c++ thread-safety shared-ptr atomic

我尝试使用线程安全的shared_ptr创建一个类。我的用例是shared_ptr属于类的对象,其行为类似于单例(CreateIfNotExist函数可以在任何时间点由任何线程运行)。

基本上,如果指针为null,则设置它的值的第一个线程获胜,而同时创建它的所有其他线程使用获胜线程的值。

以下是我到目前为止(注意,唯一有问题的函数是CreateIfNotExist()函数,其余用于测试目的):

#include <memory>
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

struct A {
    A(int a) : x(a) {}
    int x;
};

struct B {
    B() : test(nullptr) {}

    void CreateIfNotExist(int val) {
        std::shared_ptr<A> newPtr = std::make_shared<A>(val);
        std::shared_ptr<A> _null = nullptr;
        std::atomic_compare_exchange_strong(&test, &_null, newPtr);
    }

    std::shared_ptr<A> test;
};

int gRet = -1;
std::mutex m;

void Func(B* b, int val) {
    b->CreateIfNotExist(val);
    int ret =  b->test->x;

    if(gRet == -1) {
        std::unique_lock<std::mutex> l(m);
        if(gRet == -1) {
            gRet = ret;
        }
    }

    if(ret != gRet) {
        std::cout << " FAILED " << std::endl;
    }
}

int main() {
    B b;

    std::vector<std::thread> threads;
    for(int i = 0; i < 10000; ++i) {
        threads.clear();
        for(int i = 0; i < 8; ++i) threads.emplace_back(&Func, &b, i);
        for(int i = 0; i < 8; ++i) threads[i].join();
    }
}

这是正确的方法吗?有没有更好的方法来确保所有调用CreateIfNotExist()的线程同时使用相同的shared_ptr?

1 个答案:

答案 0 :(得分:4)

沿着这些方向的东西也许:

[{'ID': 123, 'Balance': 45, 'Comments': None}, {'ID': 456, 'Balance': 78, 'Comments': None}]