共享指针控制块的线程安全
Thread Safety of Shared Pointers' Control Block
我正在开发一个使用共享指针的小程序。我有一个简单的 class“事物”,它只是一个具有整数属性的 class:
class Thing{
public:
Thing(int m){x=m;}
int operator()(){
return x;
}
void set_val(int v){
x=v;
}
int x;
~Thing(){
std::cout<<"Deleted thing with value "<<x<<std::endl;
}
};
我有一个简单的函数“fun”,它接受一个 shared_ptr 实例和一个整数值 index,它只是跟踪哪个线程正在输出给定值。该函数打印出传递给函数的索引值,以及作为参数传入的共享指针的引用计数
std::mutex mtx1;
void fun(std::shared_ptr<Thing> t1,int index){
std::lock_guard <std::mutex> loc(mtx1);
int m=t1.use_count();
std::cout<<index<<" : "<<m<<std::endl;
}
在 main 中,我创建了一个共享指针的实例,它是一个 Thing 对象的包装器,如下所示:
std::shared_ptr<Thing> ptr5(nullptr);
ptr5=std::make_shared<Thing>(110);
(为了异常安全而以这种方式声明)。
然后我创建了 3 个线程,每个线程都创建了一个执行 fun() 函数的线程,该函数将 ptr5 共享指针作为参数并增加索引值:
std::thread t1(fun,ptr5,1),t2(fun,ptr5,2),t3(fun,ptr5,3);
t1.join();
t2.join();
t3.join();
我在这里的思考过程是,由于每个共享指针控制块成员函数都是线程安全的,因此在 fun() 函数中对 use_count() 的调用不是原子指令,因此不需要锁定。然而,运行 没有和没有 lock_guard,这仍然会导致竞争条件。我希望看到输出:
1:2
2:3
3:4
由于每个线程都会生成对原始共享指针的新引用,因此 use_count() 每次都会递增 1 个引用。但是,由于某些竞争条件,我的输出仍然是随机的。
在多线程环境中,use_count()
是近似值。来自 cppreference :
In multithreaded environment, the value returned by use_count is approximate (typical implementations use a memory_order_relaxed load)
shared_ptr
的控制块在其他方面是线程安全的:
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object.
看到过时的 use_count()
并不表示控制块已被竞争条件损坏。
请注意,这不会扩展到修改指向的对象。它不为指向的对象提供同步。只有 shared_ptr
和控制块的状态受到保护。
我正在开发一个使用共享指针的小程序。我有一个简单的 class“事物”,它只是一个具有整数属性的 class:
class Thing{
public:
Thing(int m){x=m;}
int operator()(){
return x;
}
void set_val(int v){
x=v;
}
int x;
~Thing(){
std::cout<<"Deleted thing with value "<<x<<std::endl;
}
};
我有一个简单的函数“fun”,它接受一个 shared_ptr 实例和一个整数值 index,它只是跟踪哪个线程正在输出给定值。该函数打印出传递给函数的索引值,以及作为参数传入的共享指针的引用计数
std::mutex mtx1;
void fun(std::shared_ptr<Thing> t1,int index){
std::lock_guard <std::mutex> loc(mtx1);
int m=t1.use_count();
std::cout<<index<<" : "<<m<<std::endl;
}
在 main 中,我创建了一个共享指针的实例,它是一个 Thing 对象的包装器,如下所示:
std::shared_ptr<Thing> ptr5(nullptr);
ptr5=std::make_shared<Thing>(110);
(为了异常安全而以这种方式声明)。
然后我创建了 3 个线程,每个线程都创建了一个执行 fun() 函数的线程,该函数将 ptr5 共享指针作为参数并增加索引值:
std::thread t1(fun,ptr5,1),t2(fun,ptr5,2),t3(fun,ptr5,3);
t1.join();
t2.join();
t3.join();
我在这里的思考过程是,由于每个共享指针控制块成员函数都是线程安全的,因此在 fun() 函数中对 use_count() 的调用不是原子指令,因此不需要锁定。然而,运行 没有和没有 lock_guard,这仍然会导致竞争条件。我希望看到输出:
1:2 2:3 3:4
由于每个线程都会生成对原始共享指针的新引用,因此 use_count() 每次都会递增 1 个引用。但是,由于某些竞争条件,我的输出仍然是随机的。
在多线程环境中,use_count()
是近似值。来自 cppreference :
In multithreaded environment, the value returned by use_count is approximate (typical implementations use a memory_order_relaxed load)
shared_ptr
的控制块在其他方面是线程安全的:
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object.
看到过时的 use_count()
并不表示控制块已被竞争条件损坏。
请注意,这不会扩展到修改指向的对象。它不为指向的对象提供同步。只有 shared_ptr
和控制块的状态受到保护。