使用原子和互斥锁 c++ 在类内部进行线程化
Posted
技术标签:
【中文标题】使用原子和互斥锁 c++ 在类内部进行线程化【英文标题】:Threading inside class with atomics and mutex c++ 【发布时间】:2016-12-05 05:19:05 【问题描述】:我编写了这个示例程序来模仿我在一个更大的程序中尝试做的事情。
我有一些数据将来自用户并被传递到线程中进行一些处理。我在数据周围使用互斥锁,当有数据时,标志会发出信号。
使用 lambda 表达式,是否将指向 *this 的指针发送到线程?我似乎在 cout 声明中得到了我期望的行为。
是否在数据周围正确使用了互斥锁?
将原子和互斥锁作为类的私有成员是一个好的举措吗?
foo.h
#pragma once
#include <atomic>
#include <thread>
#include <vector>
#include <mutex>
class Foo
public:
Foo();
~Foo();
void StartThread();
void StopThread();
void SendData();
private:
std::atomic<bool> dataFlag;
std::atomic<bool> runBar;
void bar();
std::thread t1;
std::vector<int> data;
std::mutex mx;
;
foo.c
#include "FooClass.h"
#include <thread>
#include <string>
#include <iostream>
Foo::Foo()
dataFlag = false;
Foo::~Foo()
StopThread();
void Foo::StartThread()
runBar = true;
t1 = std::thread([=] bar(); );
return;
void Foo::StopThread()
runBar = false;
if(t1.joinable())
t1.join();
return;
void Foo::SendData()
mx.lock();
for (int i = 0; i < 5; ++i)
data.push_back(i);
mx.unlock();
dataFlag = true;
void Foo::bar()
while (runBar)
if(dataFlag)
mx.lock();
for(auto it = data.begin(); it < data.end(); ++it)
std::cout << *it << '\n';
mx.unlock();
dataFlag = false;
main.cpp
#include "FooClass.h"
#include <iostream>
#include <string>
int main()
Foo foo1;
std::cout << "Type anything to end thread" << std::endl;
foo1.StartThread();
foo1.SendData();
// type something to end threads
char a;
std::cin >> a;
foo1.StopThread();
return 0;
【问题讨论】:
使用 std::lock_guardjoin()
它或者detach()
@DmitryKatkevich 为什么?他稍后会join()
ing...
我更喜欢保存 detach
以备不时之需
我会将您的作业转移到 dataFlag
到锁内。现在我可以看到它在外面的潜在问题。
【参考方案1】:
您确保线程是使用 RAII 技术连接的?查看。
所有数据访问/修改都通过atomic
s 或mutex
s 保护?查看。
互斥锁使用std::lock_guard
?没有。使用std::lock_guard
将您的lock()
和unlock()
调用与RAII 一起包装。这确保即使在锁内发生异常,锁也会被释放。
将原子和互斥锁作为类的私有成员是一个好的举措吗?
它既不好也不坏,但在这种情况下,Foo
是 std::thread
的包装器,它可以工作并控制同步,这是有道理的。
使用 lambda 表达式,是否将指向 *this 的指针发送到线程?
是的,您也可以使用t1 = std::thread([this]bar(););
使其更明确。
就目前而言,在锁定之后分配dataFlag
,您可能会遇到问题。如果您调用SendData
两次以使bar
处理第一个,但在设置dataFlag = false
之前暂停,以便第二个调用添加数据,则将标志设置为true
仅让bar
将其设置回false
。然后,您将拥有已“发送”但bar
认为没有任何要处理的数据。
可能还有其他棘手的情况,但这只是一个例子;将其移入锁中可以解决该问题。
例如,您的 SendData
应如下所示:
void Foo::SendData()
std::lock_guard<std::mutex> guard(mx);
for (int i = 0; i < 5; ++i)
data.push_back(i);
dataFlag = true;
【讨论】:
以上是关于使用原子和互斥锁 c++ 在类内部进行线程化的主要内容,如果未能解决你的问题,请参考以下文章