繁体   English   中英

使用shared_ptr多线程

[英]Multithreading with shared_ptr

我将我的简单多线程应用程序用作简单的测试平台。 我要实现的是修改传递给多个线程的一个变量的值,并在完成所有操作后读取结果。

#include <iostream>
#include <memory>
#include <thread>
#include <mutex>

void updateValue(const std::shared_ptr<int>& value);

int main()
{
    auto sp = std::make_shared<int>(0);
    std::thread incrementThread_1(updateValue,sp);
    std::thread incrementThread_2(updateValue,sp);
    incrementThread_1.join();
    incrementThread_2.join();
    std::cout << *sp << std::endl;
}

void updateValue(const std::shared_ptr<int>& value)
{
    std::mutex g_i_mutex;
    for(int i = 0; i<100;i++)
    {
        std::unique_lock<std::mutex> lk(g_i_mutex);
        (*value)++;
        lk.unlock();
    }
}

目前,它只是崩溃了。 我在调试窗口中没有任何有意义的信息,因此也无济于事。 有人可以告诉我我做错了什么吗?

需要指出的一件事- 我不想使用全局变量 ,因为这些函数最初位于不同的文件中。

线程之间共享的数据需要附带自己的互斥锁(与完全相同的线程集共享),并且要求所有访问者都同意使用该互斥锁来序列化访问。

一个典型的解决方案是提供一个自定义类型来封装此职责。 使用这种方法,您的代码将大致如下所示:

struct SyncInt
{
    int n = 0;
    std::mutex mx;
};

void updateValue(SyncInt & value)
{
    for (int i = 0; i != 100; ++i)
    {
        std::lock_guard<std::mutex> lock(value.mx);
        ++value.n;
    }
}

int main()
{
    SyncInt v;
    std::thread t1(updateValue, std::ref(v)), t2(updateValue, std::ref(v));
    t1.join();
    t2.join();
    std::cout << v.n << "\n";
}

(请注意,示例中的共享指针对于并发问题并不重要,因为所有代码都只使用了指针,而指针本身从未使用过。)

目前,它只是崩溃了。 有人可以告诉我我做错了什么吗?

您实际上是从2个不同的线程更新共享变量value ,而没有任何同步。 这是数据争用条件,即未定义行为。 最简单的解决方法是将g_i_mutex全局:

#include <iostream>
#include <memory>
#include <thread>
#include <mutex>

std::mutex g_i_mutex;

void updateValue(const std::shared_ptr<int>& value);

int main()
{
    auto sp = std::make_shared<int>(0);
    std::thread incrementThread_1(updateValue,sp);
    std::thread incrementThread_2(updateValue,sp);
    incrementThread_1.join();
    incrementThread_2.join();
    std::cout << *sp << std::endl;
}

void updateValue(const std::shared_ptr<int>& value)
{
    for(int i = 0; i<100;i++)
    {
        std::unique_lock<std::mutex> lk(g_i_mutex);
        (*value)++;
        lk.unlock();
    }
}

没有全局变量的另一个解决方案:

#include <iostream>
#include <memory>
#include <thread>
#include <mutex>

void updateValue(const std::shared_ptr<int>& value, std::mutex& g_i_mutex)
{
    for(int i = 0; i<100;i++)
    {
        std::unique_lock<std::mutex> lk(g_i_mutex);
        (*value)++;
        lk.unlock();
    }
}

int main()
{
    auto sp = std::make_shared<int>(0);
    std::mutex g_i_mutex;
    std::thread incrementThread_1(updateValue, sp, std::ref(g_i_mutex));
    std::thread incrementThread_2(updateValue, sp, std::ref(g_i_mutex));
    incrementThread_1.join();
    incrementThread_2.join();
    std::cout << *sp << std::endl;
}

根据问题的实质,在这种情况下根本不需要使用shared_ptr 您只需要一个atomic<int>

您想要使用类似这样的数据结构,该结构将互斥体与它保护访问的数据紧密相关:

class somethingShared
{
    int        m_value;
    std::mutex m_mtx;

    public:
    somethingShared( int initialVal ) : m_value( initialVal ) { }

    void increment()
    {
        std::unique_lock<std::mutex> lk(m_mtx);
        ++m_value;
    }

    int value() const { return m_value; }

};

void updateValue( somethingShared & value)
{
    for ( int i = 0; i < 100; ++i )
    {
        value.increment();
    }
}

注意:我还没有编译或运行它,只是为了显示一般想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM