2017-09-06 2 views
0

이미지를 디스크에 원시 데이터로 덤프하는 스레드가 있습니다. 그것은 몇 분 동안 잘 작동하고 갑자기 아무것도하는 것을 멈 춥니 다.스레드가 임의의 시간에 아무런 오류없이 임의의 위치에서 실행 중지

명령 줄 출력을 통해 루프 내의 임의의 위치에서 멈추는 것을 발견했습니다.

이 프로그램은 스레드에서 이렇게 에러/예외/무엇을 (내 이미지 버퍼가 가득 차면 때문에 스레드가 실행되지 중지 직후 충돌)이 thread 내에서 충돌하지 않습니다.

여기 내 코드의 스케치입니다 :

class ImageWriter 
{ 
public: 
    // constructor, destructor 
    void continueWriting(); 
private: 
    void writeImages(); 
    std::thread m_WriterThread; 
    bool m_WriterThreadRunning; 
    std::mutex m_ThreadRunningMutex; 
    ImageManager * m_ImageManager; 
}; 

ImageWriter::continueWriting() 
{ 
    // whenever a new image is acquired, this function is called 
    // so if the thread has finished, it needs to be restarted 
    // this function is also used for the first start of writing 
    m_ThreadRunningMutex.lock(); 
    if (m_WriterThreadRunning) 
    { 
    m_ThreadRunningMutex.unlock(); 
    } 
    else 
    { 
    m_ThreadRunningMutex.unlock(); 
    if(m_WriterThread.joinable()) 
    { 
     m_WriterThread.join(); 
    } 
    m_WriterThreadRunning = true; 
    m_WriterThread = std::thread(&ImageWriter::writeImages, this); 
    } 
} 

void ImageWriter::writeImages() 
{ 
    while (true) 
    { 
    // MyImage is a struct that contains the image pointer and some metadata 
    std::shared_ptr<MyImage> imgPtr = m_ImageManager->getNextImage(m_uiCamId); 
    if(imgPtr == nullptr) 
    { 
     // this tells the ImageWriter that currently there are no further images queued 
     break; 
    } 

    // check whether the image is valid. If it's not, skip this image and continue with the next one 
    [...] 

    // create filename 
    std::stringstream cFileNameStr; 
    cFileNameStr << [...]; 
    std::ofstream cRawFile(cFileNameStr.str().c_str(), std::ios::out | std::ios::binary); 

    unsigned char * ucDataPtr = imgPtr->cImgPtr; 
    if(cRawFile.is_open()) 
    { 
     // calculate file size 
     unsigned int uiFileSize = [...]; 
     cRawFile.write(reinterpret_cast<char*>(ucDataPtr), uiFileSize); 
     cRawFile.close(); 
    } 

    // dump some metadata into a singleton class for logging 
    [...] 
    } 

    m_ThreadRunningMutex.lock(); 
    m_WriterThreadRunning = false; 
    m_ThreadRunningMutex.unlock(); 
} 

ImageManager은 이미지 수집을 담당하고, 획득 된 영상을 큐 클래스입니다. 또한 continueWriting()을 트리거합니다. 이미지는 획득 한 것보다 빨리 기록 될 수 있으므로 continueWriting() 메커니즘이 필요합니다.

왜이 스레드는 임의의 위치에 어떤 오류없이 임의의 시간에 실행을 중지합니까?

Valgrind는 내 제어 내에서 아무것도 산출하지 않습니다. 스레드의 우선 순위 설정을 시도했지만 아무런 차이가 없습니다. 다른 디스크를 사용해 보았지만 아무런 차이가 없었습니다.

+0

난 당신이 m_WriterThreadRunning을 읽고 뮤텍스 잠금에서 거짓 쓸 수 있지만 진정한 보호되지 않은 쓰기 이해하지? 이 뮤텍스는 오직 하나의 부울을 보호하기위한 것입니까? 대신 원자를 사용하십시오. 스레드를 시작/중지하지는 않겠지 만 이미지가 대기열에 없으면 continueWriting이 스레드에 대기 신호를 보냅니다. –

+0

m_WriterThreadRunning 쓰기는 이전 스레드가 연결되고 새 스레드가 시작되기 전에 발생하므로 어떤 경쟁 조건도 발생할 수 없습니다. 대기 메커니즘이 적합합니다. 나에게 일어나지도 않았다. 문제가 해결되지 않아도 읽을 수 있어야하므로 좋은 생각입니다! –

+0

증상 : 1) 다중 스레드. 2) 명시 적 뮤텍스 사용. 3) 잠시 사용 후 잠급니다. 진단 : 합리적인 의심의 여지없이 교착 상태가 발생합니다. –

답변

0

두 분기의 스레드를 즉시 잠금 해제하는 것으로 나타났습니다. 당신이하고있는 일은 모두 부울을 읽는 것이므로, 아마도 완전히 자물쇠를 사용하지 않아야 할 것입니다. 읽기는 일반적으로 동기화가 필요한 작업이 아닙니다 (스트림 읽기 또는 위치 할당 해제와 같은 부작용이없는 경우 제외)

다음을 고려하십시오. 사실이되기 전에는 해당 bool의 True 값을 읽지 않습니다. 당신이하는 일 모두가 읽혀지기 때문에, 당신은 그 기능이 그 bool에 잘못된 값을 할당하는 위험을 감수하지 않을 것입니다. 이미 스레드에 합류 할 때까지 여기에 bool에 새 값을 할당하지 마십시오.

내가 여기서 무슨 일이 일어나고 있는지 가정 줄은 코드가 뮤텍스를 잠그고, 다른 스레드가 쓰기를 시도하지만이 잠겨 할 수 없기 때문이다.

+0

메모리 장벽에 대해 배우고 싶을 수 있습니다. – stark

관련 문제