线程化类成员函数;线程初始化通过初始化列表

问题描述:

我试图从类成员函数创建一个胎面,并通过类构造函数初始化程序列表初始化所述线程。线程化类成员函数;线程初始化通过初始化列表

在调用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; 
} 

这是怎么发生的?

您正在观察的问题是由列表初始化之前启动的线程引起的,给出数据竞赛,这会导致未定义的行为。添加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++); 
} 

,同样在访问列表中的其他功能。

+0

这对我来说没有意义,为什么取消注释'printf()'允许代码无例外地执行。我的印象是,简单地使用list :: push和list :: pop函数可以同时运行,没有问题。另外,将主线程中的while循环替换为'while(true){}'仍然会导致异常。 – KKlouzal 2014-09-03 10:40:57

+0

@KKlouzal:未定义的行为往往没有意义。不,标准容器不同步;你需要自己照顾自己。确实还有另外一个问题,我会在答案中加入。 – 2014-09-03 10:47:07

+0

非常感谢您提供的所有信息。我不知道在类定义中声明变量的顺序表示它们被初始化的顺序。 – KKlouzal 2014-09-03 10:51:38