【问题标题】:Is it a good way to keep thread-safety to synchronize the object?这是保持线程安全以同步对象的好方法吗?
【发布时间】:2021-02-08 08:55:07
【问题描述】:

根据shared_ptr/atomic,我们知道shared_ptr::reset() 是线程安全的。 防止被其他线程访问的对象被释放。我创建了一个store ptr 来保留过期的对象。 那么,以下代码在任何时候都是线程安全的?

class data_info
{
    shared_ptr<sample> using;
    shared_ptr<sample> store;
}

// function1 and function2 are used in different threads;
void function1(data_info &a)
{
    a.using->do_something();
}

void function2(data_info &a)
{
    a.store = a.using;
    a.using.reset(new sample());
}

我写了一个演示来确认我的想法

#include <bits/stdc++.h>
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>

using namespace std;

#define ATOMIC_READLOCK(stored_data_ptr) \
    {                                    \
        auto atomic_readlock_##name = stored_data_ptr;

#define ATOMIC_READLOCK_RELEASE() \
    }

#define ATOMIC_WRITELOCK(stored_data_ptr, new_data_ptr) \
    stored_data_ptr = new_data_ptr

class bar
{
public:
    bar() : num(1) {}
    explicit bar(int x) : num(x) {}
    int get_num()
    {
        return num;
    }
    void set_num(int x)
    {
        num = x;
    }

private:
    int num;
};

vector<int> v;

shared_ptr<bar> ptr_1, ptr_2;

void get_func()
{
    for (int i = 0; i < 100000; i++)
    {
        ATOMIC_READLOCK(ptr_1);
        v.push_back(ptr_1->get_num());
        ATOMIC_READLOCK_RELEASE();
    }
}

void set_func()
{
    for (int i = 0; i < 100000; i++)
    {
        ptr_2 = make_shared<bar>(i);
        ATOMIC_WRITELOCK(ptr_1, ptr_2);
    }
}

int main()
{
    std::thread t1(get_func);
    std::thread t2(set_func);
    t1.join();
    t2.join();
}

但它会发生核心转储

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./reset'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000555a2a075c58 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() ()
[Current thread is 1 (Thread 0x7f70244ec700 (LWP 30265))]
(gdb) where
#0  0x0000555a2a075c58 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() ()
#1  0x0000555a2a0758b9 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() ()
#2  0x0000555a2a075790 in std::__shared_ptr<bar, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() ()
#3  0x0000555a2a0757c2 in std::shared_ptr<bar>::~shared_ptr() ()
#4  0x0000555a2a0753cc in get_func() ()
#5  0x0000555a2a076069 in void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) ()
#6  0x0000555a2a075b3e in std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) ()
#7  0x0000555a2a077b52 in decltype (__invoke((_S_declval<0ul>)())) std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) ()
#8  0x0000555a2a077af0 in std::thread::_Invoker<std::tuple<void (*)()> >::operator()() ()
#9  0x0000555a2a077a3c in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() ()
#10 0x00007f70251706df in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#11 0x00007f7024c836db in start_thread (arg=0x7f70244ec700) at pthread_create.c:463
#12 0x00007f70249aca3f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

【问题讨论】:

    标签: c++ multithreading locking shared-ptr atomic


    【解决方案1】:

    我认为您的代码是线程安全的。但我也建议另一种解决方案,其中访问类成员的线程将获得shared_ptr 的所有权。它本质上使整个场景成为线程安全的。

    void function1(data_info &a) {
        auto member = a.member;
        member->do_something();
    }
    
    void function2(data_info &a) {
        a.member = std::make_shared<sample>();
    }
    

    【讨论】:

    • 在你的代码中,如果function1(thread1)是do_something,function2(t2)释放这个对象,function1现在正在使用什么
    • @Smilencer 1. auto member in function1 取得所有权。 2.function2释放所有权。但是由于function1 持有auto member 和auto member 持有引用计数,所以下面的对象不会被释放。
    • 但在这种情况下,您将使用 auto member,而不是 a.member
    • @Алексей Неудачин 我看不出有什么不同。
    • 我们看不到 sample 的推出,所以很难阅读。是的,它会工作
    【解决方案2】:

    然后你将如何删除保留shared_ptr。当 .dosmth() 在某处被调用时,reserve 可能会超出范围。
    做这些你需要weak_ptr。 https://stackoverflow.com/questions/63291791/does-weak-ptrs-lock-will-always-work-in-statement-instore-com-r-lock-i?noredirect=1#comment111921096_63291791

    更新: 是的,看起来很安全

    更新2: 所以我们在这里:
    对于weak_ptr 的.lock() 其shared_ptr 的参考计数器获得+1,而lock() 的东西还没有完成(见链接)。
    对于-&gt; 的shared_ptr 它没有。刚刚测试过了。

    所以它不是线程安全的,它不会工作。
    看到它dosmth() 应该比所有其他人运行更长的时间并使用this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      • 2016-07-16
      • 2016-05-15
      相关资源
      最近更新 更多