You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程下解引用this与shared_ptr是否线程安全?代码安全性问询

问题

我实现了一个用mutex保证多线程读写的队列,代码里把this指针和shared_ptr类型的m_mulque传递给了读写线程。想咨询:解引用this指针和m_mulque是否线程安全?也就是下面的代码是否线程安全,运行时有没有未定义行为?

#include <mutex>
#include <queue>

struct multithreaded_queue
{
    void push(const std::size_t i) 
    {
        std::lock_guard lock(m_mutex);
        m_queue.push(i);
    };

    void try_pop() 
    {
        std::lock_guard lock(m_mutex);
        m_queue.pop();
    };

private:
    std::queue<std::size_t> m_queue;
    mutable std::mutex m_mutex;
};
class example
{
public:
    example()
    {
        m_mulque = std::make_shared<multithreaded_queue>();
    };

    void run()
    {
        auto writer = [this]()
        {
            for (std::size_t i = 0; i < 1000; i++)
            {
                m_mulque->push(i);
            };
        };

        auto reader = [this]()
        {
            for (std::size_t i = 0; i < 1000; i++)
            {
                m_mulque->try_pop();
            };
        };

        std::thread writer1(writer);
        std::thread reader1(reader);
        std::thread reader2(reader);

        writer1.join();
        reader1.join();
        reader2.join();
    };

private:
    std::shared_ptr<multithreaded_queue> m_mulque;
};
int main(int argc, char* argv[])
{
    example ex;
    ex.run(); //Is this thread safe to call?
};
回答

1. 解引用this指针的安全性

你的代码里,run()创建的lambda捕获了this,但主线程中的example对象ex是在栈上创建的,而且run()会等待所有子线程执行完毕才返回(调用了join())。这意味着子线程存活期间,ex肯定不会被销毁,所以解引用this是安全的,不会出现访问已销毁对象的问题。

2. 解引用m_mulque的安全性

m_mulque是std::shared_ptr类型,它的引用计数操作是原子的,本身具备线程安全性。再结合你的代码逻辑:

  • 构造函数在主线程中完成了m_mulque的初始化,之后子线程只读取m_mulque,没有任何修改操作,不存在多线程竞争修改m_mulque的场景;
  • 子线程通过m_mulque调用队列的push/try_pop时,队列内部已经用std::mutex做了同步,这部分的线程安全是有保障的。

所以解引用m_mulque也是线程安全的。

3. 代码存在的未定义行为

虽然上面两部分没问题,但你的代码有个明显的隐患:multithreaded_queue::try_pop()没有检查队列是否为空就直接调用pop()。写线程只push了1000个元素,但两个读线程总共要执行2000次pop,必然会出现队列空的时候调用pop()的情况——而标准库的std::queue::pop()要求队列必须非空,否则行为属于未定义。

总结

  • 解引用this和m_mulque是线程安全的;
  • 代码整体存在未定义行为,原因是读线程可能在队列空时执行pop()。你需要修改try_pop()函数,先检查队列状态:

修改后的try_pop()示例:

bool try_pop() 
{
    std::lock_guard lock(m_mutex);
    if (m_queue.empty()) {
        return false; // 队列空,返回操作失败
    }
    m_queue.pop();
    return true;
};

同时读线程的循环逻辑也要调整,改成直到成功完成1000次pop:

auto reader = [this]()
{
    std::size_t success_count = 0;
    while (success_count < 1000)
    {
        if (m_mulque->try_pop()) {
            success_count++;
        }
        // 可选:加短暂休眠避免空转占用CPU
        // std::this_thread::sleep_for(std::chrono::microseconds(1));
    };
};

内容的提问来源于stack exchange,提问作者Vero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:45:27