C++ 线程化类成员函数;通过初始值设定项列表进行线程初始化
我试图从一个类成员函数创建一个线程,并通过类构造函数初始化器列表初始化所述线程 在执行线程时,调用C++ 线程化类成员函数;通过初始值设定项列表进行线程初始化,c++,multithreading,C++,Multithreading,我试图从一个类成员函数创建一个线程,并通过类构造函数初始化器列表初始化所述线程 在执行线程时,调用Receive\u List.push\u back(CurVal++)时会引发异常,但是只需将printf()作为函数中的第一条指令即可避免此异常 #include <thread> #include <list> class SomeClass { std::thread Receive_Thread; std::list<unsigned in
Receive\u List.push\u 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;
}
#包括
#包括
上课
{
std::线程接收线程;
std::列表接收列表;
无效接收_Main()
{
//printf(“避免异常的黑客方式”\n);
const unsigned int MaxVal=3000;
无符号整数曲线=0;
while(曲线<最大值)
{
接收列表。向后推(CurVal++);
}
}
公众:
SomeClass():
接收线程(std::Thread(&SomeClass::接收线程Main,this))
{}
~SomeClass()
{
Receive_Thread.join();
}
void ProcessReceiveList()
{
如果(!Receive_List.empty())
{
printf(“接收到的值:%i\n”,Receive_List.front());
Receive_List.pop_front();
}
}
bool IsReceiveEmpty()
{
return Receive_List.empty();
}
};
int main()
{
SomeClass*MyObject=新的SomeClass();
//
//睡眠1秒,让线程开始填充列表
std::this_thread::sleep_for(std::chrono::seconds(1));
而(!MyObject->IsReceiveEmpty())
{
MyObject->ProcessReceiveList();
}
删除MyObject;
标准::系统(“暂停”);
返回0;
}
为什么会发生这种情况?您观察到的问题是由于在初始化列表之前启动的线程导致了数据竞争,从而导致未定义的行为。添加
printf
会延迟对列表的首次访问,因此初始化更有可能在访问之前完成。但这并不能解决数据竞争问题;可以通过在线程之前声明列表来修复该问题:
std::list<unsigned int> Receive_List;
std::thread Receive_Thread;// WARNING: must be initialised last
std::list接收\u list;
std::thread Receive_thread;//警告:必须最后初始化
您还有一个问题:对由一个线程修改并由另一个线程更新的数据的所有访问都必须同步;通常是用一根绳子保护它。如果没有同步,您将再次面临数据竞争,从而导致未定义的行为
因此,向类中添加一个互斥体以保护列表:
#include <mutex>
class SomeClass {
std::mutex mutex;
//...
};
#包括
上课{
std::互斥互斥;
//...
};
并在访问列表时锁定它
while (CurVal < MaxVal)
{
std::lock_guard<std::mutex> lock(mutex);
Receive_List.push_back(CurVal++);
}
while(曲线
同样,在访问列表的其他函数中。这对我来说没有意义,为什么取消对
printf()
的注释会允许代码毫无例外地执行。我的印象是,简单地使用list::push和list::pop函数可以并行运行,而不会出现任何问题。另外,将主线程中的while循环替换为while(true){}
仍然会导致异常。@KKlouzal:未定义的行为通常没有意义。不,标准容器不同步;你需要自己照顾好。确实还有一个问题,我将补充回答。非常感谢您提供的所有信息。我不知道在类定义中声明变量的顺序表示它们被初始化的顺序。