2014-09-03 2 views
0

클래스 멤버 함수에서 트레드를 만들고 클래스 생성자 초기화 프로그램 목록을 통해 스레드를 초기화하려고합니다.스레딩 클래스 멤버 함수; 초기화 도구 목록을 통한 스레드 초기화

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; 
} 

왜 이런 일이 발생합니까?

답변

2

관찰중인 문제는 목록이 초기화되기 전에 스레드가 시작되어 데이터 경주가 인 결과로 나타나며 정의되지 않은 동작으로 이어집니다. printf을 추가하면 목록에 대한 첫 번째 액세스가 지연되므로 초기화 전에 액세스가 완료 될 가능성이 높아집니다. 이것은 이 아니고 데이터 레이스를 수정합니다.

std::list<unsigned int> Receive_List; 
std::thread Receive_Thread;// WARNING: must be initialised last 

당신은 더 문제가있다 : 그것은 전에 스레드를 목록 를 선언하여 고정 할 수있는 모든 동기화해야합니다 다른에 의해 하나 개의 스레드에 의해 수정 및 업데이트 데이터에 액세스; 대개는 mutex으로 지키십시오. 동기화가 없으면 데이터 경쟁이 다시 발생하여 정의되지 않은 동작이 발생합니다. 당신이 목록을

while (CurVal < MaxVal) 
{ 
    std::lock_guard<std::mutex> lock(mutex); 
    Receive_List.push_back(CurVal++); 
} 

마찬가지로 목록에 액세스 다른 기능에 액세스 할 때

#include <mutex> 

class SomeClass { 
    std::mutex mutex; 
    //... 
}; 

을 잠급 :

그래서 목록을 보호하기 위해 클래스에 뮤텍스를 추가 할 수 있습니다.

+0

왜'printf()'를 주석 해제하면 예외없이 코드를 실행할 수 있습니다. 나는 단순히 list :: push와 list :: pop 함수를 사용하는 것이 문제없이 동시에 실행될 수 있다는 인상을 받았다. 또한 주 스레드의 while 루프를'while (true) {}'로 바꾸면 여전히 예외가 발생합니다. – KKlouzal

+0

@KKlouzal : 정의되지 않은 동작은 종종 의미가 없습니다. 표준 컨테이너는 동기화되지 않습니다. 너 자신을 돌봐 줘야 해. 참으로 또 다른 문제가 있는데, 나는이 질문에 답을 추가 할 것입니다. –

+0

모든 정보를 제공해 주셔서 감사합니다. 클래스 정의에서 변수를 선언 한 순서가 초기화 된 순서를 나타냈다는 것을 알지 못했습니다. – KKlouzal

관련 문제