关于共享_ptr的种族条件示例
https://godbolt.org/z/neypyqdqk”中没有种族条件
#include<memory>
#include<thread>
std::shared_ptr<int> g_s = std::make_shared<int>(1);
void f1(std::shared_ptr<int> sp)
{
std::shared_ptr<int>l_s1 = sp; // read g_s
}
void f2()
{
std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
std::thread th(f1, g_s);
th.detach();
g_s = l_s2; // write g_s
}
int main()
{
std::thread(f2).join();
}
为什么在代码snippet 下面?
#include<memory>
#include<thread>
std::shared_ptr<int> g_s = std::make_shared<int>(1);
void f1(std::shared_ptr<int>& sp)
{
std::shared_ptr<int>l_s1 = sp; // read g_s
}
void f2()
{
std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
std::thread th(f1, std::ref(g_s));
th.detach();
g_s = l_s2; // write g_s
}
int main()
{
std::thread(f2).join();
}
我目前对这个问题的想法是在第一个答案中看到的。但是我还不那么确定。 有人可以阐明这个问题吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
std :: shardy_ptr 本身不是线程 - safe )std :: shared_ptr&lt;&gt;不能从两个线程同一时间修改。
它不是线程安全的,因为为了速度而言,在共享_ptr&gt;&gt;&gt;&gt;&gt;中没有静音。
您的第一个代码片段仅通过共享_ptr&lt; gt;实例,切勿引用,因此两个线程修改了它们的不同副本。线程安全。
第二个代码段将引用到第二个线程,因此两个线程修改了共享_ptr&lt; gt;的同一实例这不是线程安全的。
为什么修改共享指针的副本是线程安全的?我们需要研究如何实施。
共享指针由对象的指针本身和指向连接两个计数器的结构的指针组成,一个计数共享指针的参考数量,第二个计数弱指针参考的数量。计数器通常在堆上分配,因此可以在共享指针的几个副本之间共享指向相同堆的计数器的指针。
当制作共享指针的副本时,将堆指向其计数器的堆复制到共享指针的其他副本,而共享指针计数器会增加原子上。
当共享指针的副本被破坏时,其计数器在原子上被减少。如果这是最后的副本,则将计数器从堆中划分。
为什么应在原子上逐渐增加/减少计数器?由于可能构造或破坏其他线程中的其他共享指针的其他副本,因此其他线程会增加/减少计数器。
如果计数器在同一时间上的不同线程上增加/减少,则应在原子上进行,以便将值读取为一个单个操作。这是避免反击本身内的比赛条件所需的。
原子操作通常是在
std::shared_ptr itself is not thread-safe, meaning that Same object (instance) of std::shared_ptr<> can't be modified same time from two threads.
It is not thread safe because there is no mutex inside implementation of shared_ptr<>, for the sake of speed.
Your first code snippet passes around only copies of shared_ptr<> instance, never references, hence two threads modify different copies of them. Which is thread safe.
Second code snippet passes reference to second thread, hence two threads modify same instance of shared_ptr<> which is not thread safe.
Why modifying a copy of shared pointer is thread safe? We need to look into how it is implemented.
Shared pointer consists of object's pointer itself and the pointer which points to the structure that conatins two counters, one counts number of references of shared pointer, second counts number of weak pointer references. Counters are usually allocated on Heap, so that pointer to same heaped counters can be shared between several copies of shared pointer.
When copy of shared pointer is made, heap pointer to its counters is copied to other copy of shared pointer, and shared pointer counter is incremented Atomically.
When copy of shared pointer is destroyed, its counter is decremented Atomically. And if it was very last copy then counters are deallocated from heap.
Why counter should be incremented/decremented Atomically? Because same time other copy of shared pointer in other thread might be constructed or destroyed, hence same time other thread will increment/decrement counter.
If counter is incremented/decremented on different threads same time, then it should happen Atomically, so that value is read-modified-stored as one single operation. This is needed to avoid race conditions within counter itself.
Atomic operations are usually done with the help of std::atomic.
首先,
std :: shared_ptr
确保访问基础控制块是安全的。对于后一个代码段,可以同时读取并写入不同线程的原始指针和指向控制块的指针,这将构成竞赛。
对于前一个,因为
void f1(std :: shared_ptr&lt; int; int sp)
通过值(即std :: shared_ptr&lt; t&gt; sp
)通过值,读取原始指针和sp
控制块的指针都独立于将所述指针分配给g_s
。因此没有数据竞赛条件。Firstly,
std::shared_ptr
guarantees access to underlying control block is thread safe.For the latter code snippet, both the raw pointer and the pointer to the control block may be concurrently read from and written to by different threads, which would constitute a race.
For the former one, since
void f1(std::shared_ptr<int> sp)
passes the parameter(i.estd::shared_ptr<T> sp
) by value, reading both the raw pointer and the pointer to the control block ofsp
is independent from assigning the said pointers tog_s
. So there is no data race condition.为了帮助想要更好地了解
shared_ptr
的数据竞赛的读者。此代码代码片段没有任何种族条件:
此下面的代码段也没有任何种族条件:
因为
std :: feek_ptr :: feek_ptr :: lock()
创建一个新的std :: shared_ptr,该shared_ptr共享托管对象的所有权。如果没有托管对象,即 *这是空的,那么返回的shared_ptr也为空。,wp.lock()
返回临时sharone_ptr
,这与名为g_s
的一个不同。To help the readers who want to better understand about the data race about
shared_ptr
.This code snippet does not have any race condition:
This code snippet below does not have any race condition, either:
Since the
std::weak_ptr::lock()
creates a new std::shared_ptr that shares ownership of the managed object. If there is no managed object, i.e. *this is empty, then the returned shared_ptr also is empty.,wp.Lock()
returns a temporaryshared_ptr
, which is different from the one namedg_s
.