使用shared_ptr进行多线程处理

时间:2017-01-05 20:31:53

标签: c++ multithreading c++11

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

#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();
    }
}

目前它只是崩溃了。我在调试窗口中没有任何有意义的信息,所以它也没有帮助。有人可以告诉我我可能做错了吗?

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

4 个答案:

答案 0 :(得分:2)

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

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

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";
}

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

答案 1 :(得分:1)

  

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

您正在从两个不同的线程更新共享变量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;
}

答案 2 :(得分:0)

根据问题的优点,根本不需要在这种情况下使用shared_ptr。您所需要的只是atomic<int>

答案 3 :(得分:-3)

您希望使用类似这样的数据结构,这会将您的互斥锁与其保护访问权限的数据强烈联系起来:

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();
    }
}

N.B。我还没有编译或运行它,只是为了展示一般的想法。