2016-10-25 1 views
0

Ich habe den folgenden Code:TBB concurrent_bounded_queue mehr Threads zugreifen

tbb::concurrent_bounded_queue<Image> camera_queue_; 
camera_queue_.set_capacity(1); 

struct Image 
{ 
    int hour_; 
    int minute_; 
    int second_; 
    int msec_; 
    QImage image_; 

    Image(){hour_ = -1; minute_ = -1; second_ = -1; msec_ = -1; image_ = QImage();} 
    Image& operator=(Image const& copy) 
    { 
     this->hour_ = copy.hour_; 
     this->minute_ = copy.minute_; 
     this->second_ = copy.second_; 
     this->msec_ = copy.msec_; 
     this->image_ = copy.image_; 
     return *this; 
    } 
}; 

In einem Qt Thema:

ThreadA:

tbb::concurrent_bounded_queue<Image> image_queue_; 
image_queue_.set_capacity(1); 
Image cur_image_; 
void Worker::process() { 

    while(1) 
    { 

     if(quit_) 
      break; 

     { 
      camera_queue_.pop(cur_image_); 
      image_queue_.push(cur_image_); 
     } 

     emit imageReady(); 
    } 

    emit finished(); 
} 

Image Worker::getCurrentImage() 
{ 
    Image tmp_image; 
    image_queue_.pop(tmp_image); 
    return tmp_image; 
} 

in einem anderen Thread:

ThreadB:

Producer::Producer(){ 
    work_ = new Worker(); 
    work_->moveToThread(workerThread_); 
    QObject::connect(workerThread_, &QThread::finished, work_, &QObject::deleteLater); 
    QObject::connect(this, &Producer::operate, work_, &Worker::process); 
    QObject::connect(work_, &Worker::imageReady, this, &Producer::displayImage); 
    QObject::connect(this, &Producer::stopDecode, work_, &Worker::stop); 
    workerThread_->start(); 
    emit operate(); 
} 

void Producer::process() { 

    while(1) 
    { 

     if(quit_) 
      break; 

     { 
      camera_queue_.push(GetImage()); 
     } 

    } 

} 


void Producer::displayImage() 
{ 
    Image tmp = std::move(work_->getCurrentImage()); 
    widget_->showImage(tmp.image_); 
} 

jedoch im Hauptthread, ich habe eine Funktion, die Benutzer ermöglicht, eine Schaltfläche klicken aktuelles Bild zu erhalten:

bool Producer::SaveImage() 
{ 

    Image img = std::move(work_->getCurrentImage()); 
    std::string fileName = std::to_string(img.hour_) + "-" + std::to_string(img.minute_) + "-" + std::to_string(img.second_) + "-" + std::to_string(img.msec_/1000) + ".jpg"; 
    std::string outFileName = folder + "/" + fileName; 

    return img.image_.save(QString::fromStdString(outFileName)); 
} 

Das Problem ist:

Wenn Benutzer rufen nicht auf die Schaltfläche klicken, um Producer :: SaveImage(), die Bilddecodierung und -darstellung läuft reibungslos. Aber wenn der Benutzer Producer :: SaveImage() aufruft, bleibt das ganze Programm hängen (Caton-Phänomen?). Die GUI-Antwort wird nicht so glatt. Je mehr Benutzer SaveImage aufrufen, desto langsamer wird die GUI-Antwort.

Kann jemand helfen, warum zu erklären? Gibt es eine Möglichkeit, das zu lösen?

Antwort

0

Warum möchten Sie die gleichzeitige Warteschlange verwenden? Es sieht so aus, als ob ein Syncronisierungsmechanismus vorhanden ist und Sie sich hauptsächlich auf ihn verlassen, anstatt concurrent_queue für die Synchronisation und Kommunikation zu verwenden, wie es angenommen wird.

Das Problem ist, dass wenn Sie Kapazität = 1 festlegen, beide Vorgänge von concurrent_bounded_queue blockieren, bis genügend Speicherplatz in der Warteschlange vorhanden ist. Z.B. Wenn die Warteschlange bereits ein Element enthält, wird die Operation push blockiert. Und da Sie Ihre Threads mit einem anderen Benachrichtigungsmechanismus steuern, können Sie einen Deadlock feststellen.

Insbesondere versuchen, die Vorgänge wie unten zu tauschen:

camera_queue_.pop(cur_image_); 
    emit imageReady(); 
    image_queue_.push(cur_image_); 

Dies sollte den Faden herzustellen, die Bilder aufnimmt (wenn ich das richtig verstehe), und es wird auf seinen image_queue_.pop() Verfahren blockiert, dann ist dieser Thread ein neues Bild einfügen und den Empfänger entsperren. Es könnte ähnliche Probleme geben, also überdenken Sie bitte Ihre gesamte Synchronisation.

+0

Die camera_queue_ (concurrent_bounded_queue mit der Kapazität 1) wird zum Abrufen von Bilddaten aus einem Live-Video verwendet. Und die image_queue_ (concurrent_bounded_queue mit der Kapazität 1) wird für den Anzeige- oder Speichervorgang verwendet. Wo ist der mögliche Stillstand? Ich habe zwei gleichzeitige Warteschlangen getrennt verwendet. Kannst du darauf hinweisen? Vielen Dank. – Johnnylin

+0

Das Signal emit imageReady() dient nur zum Aufrufen der Producer-Instanz, um das Image von image_queue_ zu erhalten, um es im Hauptthread anzuzeigen. – Johnnylin

+0

Stellen Sie sich nun vor, dass Producer immer noch ein Element in der Warteschlange hat. In der Reihenfolge der Operationen wird Push blockiert und Producer wird nicht aufgerufen. – Anton