我非常喜欢我的简单多线程应用程序,我将其用作简单的测试平台。我想要实现的是修改传递给多个线程的一个变量的值,并在完成后读取结果。
#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();
}
}
目前它只是崩溃了。我在调试窗口中没有任何有意义的信息,所以它也没有帮助。有人可以告诉我我可能做错了吗?
有一点需要指出 - 我不想使用全局变量,因为这些函数最初位于不同的文件中。
答案 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。我还没有编译或运行它,只是为了展示一般的想法。