我写了这个示例程序来模仿我在一个更大的程序中尝试做的事情。
我有一些数据来自用户并被传递到线程进行某些处理。我在数据周围使用互斥锁,标志在有数据时发出信号。
使用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;
}
答案 0 :(得分:0)
您确保使用RAII技术连接线程吗?校验。
所有数据访问/修改都是通过atomic
或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;
}