我正在嘗試創建一個線程安全的shared_ptr類。我的用例是shared_ptr屬於類的一個對象,其行爲有點像單例(CreateIfNotExist函數可以在任何時間點由任何線程運行)。正確創建thread_safe shared_ptr而不鎖定的方法?
本質上,如果指針爲空,則設置其值的第一個線程將勝出,同時創建它的所有其他線程將使用獲勝線程的值。
這裏是我到目前爲止(注意,問題的唯一功能是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?
爲什麼不把'B'不是默認contructable所以'test'必須是有效的? – NathanOliver
只需定義一個單獨的共享指針並在產生它時將它傳遞給每個線程? – sji
@sji我故意以這樣的方式構建代碼,以適合我的用例,如果沒有大量的重構,就不可能做到這一點 – Andrew