【发布时间】:2021-03-17 18:19:00
【问题描述】:
我正在开发一个使用共享指针的小程序。我有一个简单的类“事物”,它只是一个具有整数属性的类:
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 个引用。但是,由于某些竞争条件,我的输出仍然是随机的。
【问题讨论】:
-
> fun() 函数中对 use_count() 的调用不是原子指令,因此不需要锁定我认为您对什么是原子以及什么需要锁定有点困惑。跨度>
-
你能扩展一下吗?我仍然习惯于何时使用锁定以及什么被认为是原子指令。
-
原子指令是那些与
std::atomic绑定的指令。如果您从 2 个线程同时访问一个非原子对象,则需要一个锁(除非另有说明,例如std::mutex::lock)。在您的示例中,您从 3 个不同的线程访问 3 个 不同shared_ptr对象。此外,shared_ptr::use_count是常量。所以不需要锁。在评论部分有点难以扩展,但请参阅例如:stackoverflow.com/q/14127379/666785
标签: c++ multithreading smart-pointers