c++11 - 用 std::unique_ptr/std::shared_ptr 确认线程安全

标签 c++11 thread-safety shared-ptr unique-ptr

我的应用程序有一个 IRC 模块,它本质上是一个普通的客户端。由于这是大量线程,我承担插件检索例如用户昵称的风险 - 它当时有效,但解析器触发更新,更改所述昵称。
一旦另一个线程再次执行,它就会处理一个指向现在无效内存的指针,因为不可能将返回 + 复制作为原子操作。

根据下面的代码,我对此的假设是否正确?因此,我想我必须使用通常的互斥锁/解锁方法,除非有人可以确认或提出其他建议(我宁愿不必转换并返回 shared_ptr,但我想这是一个有效的选项,它是只是我打算 SWIG'ing 这个,不知道它是否不喜欢它们)。

IrcUser.h

class IrcUser : public IrcSubject
{
private:
    ...
    std::shared_ptr<std::string>    _nickname;
    std::shared_ptr<std::string>    _ident;
    std::shared_ptr<std::string>    _hostmask;
public:
    ...
    const c8*
    Ident() const
    { return _ident.get()->c_str(); }

    const c8*
    Hostmask() const
    { return _hostmask.get()->c_str(); }

    const u16
    Modes() const
    { return _modes; }

    const c8*
    Nickname() const
    { return _nickname.get()->c_str(); }

    bool
    Update(
        const c8 *new_nickname,
        const c8 *new_ident,
        const c8 *new_hostmask,
        const mode_update *new_modes
    );
};

IrcUser.cc
bool
IrcUser::Update(
    const c8 *new_nickname,
    const c8 *new_ident,
    const c8 *new_hostmask,
    const mode_update *new_modes
)
{
    if ( new_nickname != nullptr )
    {
        if ( _nickname == nullptr )
        {
            *_nickname = std::string(new_nickname);
        }
        else
        {
            _nickname.reset();
            *_nickname = std::string(new_nickname);
        }

        Notify(SN_NicknameChange, new_nickname);
    }

    ...
}

最佳答案

我建议锁定如此细粒度的级别可能(方式)过大。

我建议对 IrcUser 对象本身进行原子更新,这可能是无锁的,具体取决于您的库实现和目标架构。这是一个使用的示例

  • std::atomic_is_lock_free<std::shared_ptr>
  • std::atomic_load<std::shared_ptr>
  • std::atomic_store<std::shared_ptr>

  • http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic用于文档。

    免责声明 我不知道有多少编译器/C++ 库实现已经实现了这个 C++11 特性。

    这是它的样子:
    #include <atomic>
    #include <memory>
    #include <string>
    
    struct IrcSubject {};
    typedef char c8;
    typedef uint16_t u16;
    typedef u16 mode_update;
    
    class IrcUser : public IrcSubject
    {
        private:
            // ...
            std::string _nickname;
            std::string _ident;
            std::string _hostmask;
            u16         _modes;
        public:
            IrcUser(std::string nickname, std::string ident, std::string hostmask, u16 modes)
                : _nickname(nickname), _ident(ident), _hostmask(hostmask), _modes(modes) { }
            // ...
            std::string const& Ident()    const { return _ident; }
            std::string const& Hostmask() const { return _hostmask; }
            const u16          Modes()    const { return _modes; }
            std::string const& Nickname() const { return _nickname; }
    };
    
    //IrcUser.cc
    bool Update(std::shared_ptr<IrcUser>& user,
        std::string new_nickname,
        std::string new_ident,
        std::string new_hostmask,
        const mode_update *new_modes
    )
    {
        auto new_usr = std::make_shared<IrcUser>(std::move(new_nickname), std::move(new_ident), std::move(new_hostmask), *new_modes /* ??? */);
        std::atomic_store(&user, new_usr);
        //Notify(SN_NicknameChange, new_nickname);
        return true;
    }
    
    bool Foo(IrcUser const& user)
    {
        // no need for locking, user is thread safe
    }
    
    int main()
    {
        auto user = std::make_shared<IrcUser>("nick", "ident", "hostmask", 0x1e);
    
        mode_update no_clue = 0x04;
        Update(user, "Nick", "Ident", "Hostmask", &no_clue);
    
        {
            auto keepref = std::atomic_load(&user);
            Foo(*keepref);
        }
    }
    

    关于c++11 - 用 std::unique_ptr/std::shared_ptr 确认线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16489772/

    相关文章:

    c++ - 如何静态检查模板的类型 T 是否为 std::vector<U>,其中 U 为 float、double 或 integral

    php - 在 C 中使用 pthread 调用 php 函数

    c++ - 堆分配内存的线程安全

    c++ - boost::shared_ptr<T> 和 boost::shared_ptr<const T> 是否共享引用计数?

    c++ - 无阻塞更新缓存

    c++ - 了解模板的声明、定义和特化

    c++ - std::array 的堆分配

    c++ - 内联初始化静态常量类成员的初始化顺序保证

    java - 是否可以停止某个线程的运行?

    c++ - 如何防止删除用作共享指针的原始指针?