2017-09-06 6 views
0

イメージをrawデータとしてディスクにダンプするスレッドがあります。それは数分の間うまく動作し、突然それは何かをやめるだけです。ランダムな時間の後にランダムな位置でエラーなしにスレッドが停止する

コマンドライン出力から、ループ内のランダムな位置で停止することがわかりました。

プログラムはこのスレッド内でクラッシュしません(イメージバッファがいっぱいになってスレッドが実行を停止した直後にクラッシュします)ので、エラー/例外/スレッドからの何もありません。

ここに私のコードのスケッチです:

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を読んだり、mutexロックの下でfalseを書いても、本当に保護されていないのですか?このミューテックスは、1つのブールを保護するだけですか?代わりにアトミックを使用します。スレッドを停止/開始することはありませんが、イメージがキューにない場合はwaitのメカニズムを実装し、continueWritingは待機スレッドを停止するようにスレッドに通知します。 –

+0

m_WriterThreadRunningの書き込みは、古いスレッドがジョイントされた後、新しいスレッドが開始される前に行われます。そのため、競合状態は発生しません。 待機メカニズムが理にかなっています。私には起こりませんでした。それが問題を解決しない場合でも、それはより読みやすいはずです、良いアイデア! –

+0

症状:1)マルチスレッド。 2)明示的なミューテックスの使用。 3)短時間の使用後にロックする。診断:合理的な疑いを越えて、デッドロック状態にあります。 –

答えて

0

あなたはすぐに両方のブランチのスレッドをロック解除していることに気付きました。あなたがやっているのはブールを読んでいるだけなので、おそらくロックを完全に使わないでください。読み込みは、通常、同期を必要とする操作ではありません(ストリームの読み込みや場所の割り当て解除などの副作用がない限り)

検討:trueになる前に真の値を読み取ることはありません。あなたがしていることすべてが読まれているので、その関数がそのブールに間違った値を割り当てるリスクは決してありません。既にスレッドに参加した後でなければ、ここにboolに新しい値を代入しないでください。

ここで起こっていることは、あなたのコードがミューテックスをロックし、別のスレッドがそのスレッドに書き込もうとしているが、ロックされているのでできないと仮定します。

+0

メモリバリアについて知りたいことがあります。 – stark

関連する問題