我正在尝试从类成员函数创建一个脚本,并通过类构造函数初始化列表初始化所述线程。
执行线程时,在调用Receive_List.push_back(CurVal++)
期间抛出异常,但只需在函数中放置printf()
作为第一条指令即可避免此异常。
#include <thread>
#include <list>
class SomeClass
{
std::thread Receive_Thread;
std::list<unsigned int> Receive_List;
void Receive_Main()
{
//printf("Hacky Way Of Avoiding The Exception\n");
const unsigned int MaxVal = 3000;
unsigned int CurVal = 0;
while (CurVal < MaxVal)
{
Receive_List.push_back(CurVal++);
}
}
public:
SomeClass() :
Receive_Thread(std::thread(&SomeClass::Receive_Main, this))
{}
~SomeClass()
{
Receive_Thread.join();
}
void ProcessReceiveList()
{
if (!Receive_List.empty())
{
printf("Received Val: %i\n", Receive_List.front());
Receive_List.pop_front();
}
}
bool IsReceiveEmpty()
{
return Receive_List.empty();
}
};
int main()
{
SomeClass* MyObject = new SomeClass();
//
// Sleep for 1 second to let the thread start populating the list
std::this_thread::sleep_for(std::chrono::seconds(1));
while (!MyObject->IsReceiveEmpty())
{
MyObject->ProcessReceiveList();
}
delete MyObject;
std::system("PAUSE");
return 0;
}
为什么会这样?
答案 0 :(得分:2)
您正在观察的问题是由列表初始化之前启动的线程引起的,这会导致数据竞争,从而导致未定义的行为。添加printf
会延迟对列表的第一次访问,因此初始化更有可能在访问之前完成。这确实不修复数据竞争;它可以通过在线程之前声明列表来修复:
std::list<unsigned int> Receive_List;
std::thread Receive_Thread;// WARNING: must be initialised last
您还有一个问题:必须同步对由一个线程修改并由另一个线程更新的数据的所有访问;通常用mutex来保护它。如果没有同步,您将再次出现数据争用,从而导致未定义的行为。
所以在类中添加一个互斥锁以保护列表:
#include <mutex>
class SomeClass {
std::mutex mutex;
//...
};
并在您访问列表时将其锁定
while (CurVal < MaxVal)
{
std::lock_guard<std::mutex> lock(mutex);
Receive_List.push_back(CurVal++);
}
以及访问列表的其他函数。