2017-09-06 4 views
0

J'ai un thread qui stocke des images en tant que données brutes sur le disque. Cela fonctionne bien pendant quelques minutes et soudainement, il cesse de faire quoi que ce soit. Par la sortie de la ligne de commande, j'ai trouvé qu'il s'arrêtait à des positions aléatoires dans la boucle.Les threads s'arrêtent après un temps aléatoire à une position aléatoire sans aucune erreur

Le programme ne plante pas dans ce thread (il se bloque peu de temps après l'arrêt du thread car mon tampon d'image est plein), donc pas d'erreur/exception/rien du thread.

est ici un croquis de mon code:

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 est une classe qui prend en charge l'acquisition d'images et des files d'attente les images acquises. Il déclenche également continueWriting(). Le mécanisme continueWriting() est nécessaire, car les images peuvent être écrites plus vite qu'elles ne sont acquises.

Pourquoi ce thread s'arrête-t-il de fonctionner à des moments aléatoires à des positions aléatoires et sans aucune erreur? Valgrind ne cède rien sous mon contrôle. J'ai essayé de régler la priorité du fil, mais cela n'a fait aucune différence. J'ai aussi essayé un autre disque, mais cela ne faisait pas de différence non plus.

+0

Je ne comprends pas que vous lisez m_WriterThreadRunning et écrivez false sous mutex lock, mais écrire true non protégé? Ce mutex est-il seulement pour protéger un booléen? utilisez atomique à la place. Je ne voudrais pas arrêter/démarrer les threads - mais implémenter un mécanisme d'attente quand aucune image ne se trouve dans la file d'attente et que continueWriting ne fera que signaler au thread d'arrêter d'attendre. –

+0

Écrire m_WriterThreadRunning true se produit après que l'ancien thread est joint et avant que le nouveau ne soit démarré, donc aucune condition de concurrence ne peut s'y produire. Le mécanisme d'attente a du sens. Je ne me suis même pas présenté. Même si cela ne résout pas le problème, il devrait être plus lisible, donc bonne idée! –

+0

Symptômes: 1) multithread. 2) l'utilisation explicite de mutex. 3) se verrouille après une courte période d'utilisation. Diagnostic: au-delà de tout doute raisonnable, vous avez une situation de blocage. –

Répondre

0

J'ai remarqué que vous déverrouilliez immédiatement le fil dans les deux branches. Puisque tout ce que vous faites est de lire un bool, vous devriez probablement éviter d'utiliser des verrous entièrement. La lecture n'est généralement pas une opération nécessitant une synchronisation (sauf si elle a des effets secondaires, comme la lecture d'un flux, ou l'emplacement est désalloué, etc.)

Considérez: Vous ne lirez jamais une valeur True à partir de cette booléenne avant qu'elle ne soit vraie et puisque tout ce que vous faites est lu, vous ne courez jamais le risque que cette fonction attribue une valeur incorrecte à ce booléen. Vous n'attribuez pas une nouvelle valeur au bool ici jusqu'à ce que vous ayez déjà rejoint votre thread.

Je suppose que ce qui se passe ici est que votre code verrouille le mutex, et un autre thread essaie d'écrire dessus, mais ne peut pas le faire puisqu'il est verrouillé.

+0

Vous voudrez peut-être en savoir plus sur les barrières de la mémoire. – stark