[英]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.