2016-10-18 2 views
0

Ich habe eine DLL, die eine hohe Priorität Funktionalität hat, die in einem Thread mit hoher Priorität ausgeführt wird. Diese DLL muss den Fortschritt melden. Grundsätzlich wird ein Callback-System verwendet. Das Problem ist, dass die DLL keine Kontrolle über die Zeit hat, die der Rückruf benötigt, um abgeschlossen zu werden. Dies bedeutet, dass die Funktionalität mit hoher Priorität von der Implementierung des Rückrufs abhängt, die nicht akzeptabel ist.Machen Sie den Umfang der Sperre in threadsafe Warteschlange kleiner

Die Idee ist, eine Klasse dazwischen zu haben, die die Fortschrittsmeldungen puffert und den Rückruf aufruft.

Ich bin neu in C++ 11 und es ist Threading-Funktionalität und versuchen, die Möglichkeiten zu entdecken. Ich habe eine Implementierung, aber ich habe ein Problem (mindestens eins, das ich jetzt sehe). Wenn der Thread nach dem Warten erwacht, wird der Mutex erneut erworben und bleibt bis zum nächsten Warten erhalten. Dies bedeutet, dass die Sperre so lange akquiriert wird, wie der langwierige Vorgang fortgesetzt wird. Der Fortschritt wird hier blockiert. Im Grunde eine Menge Code für keinen Gewinn. Ich dachte daran, den Code zu ändern, aber ich weiß nicht, ob dies die korrekte Implementierung ist.

Ich denke, ich muss auf die Zustandsvariable warten, aber das sollte nicht mit dem Schloss verbunden sein. Ich sehe nicht, wie das gemacht werden kann. Übergeben Sie eine Dummy-Sperre und verwenden Sie eine andere Sperre, um die Warteschlange zu schützen? Wie sollte dieses Problem in C++ 11 angegangen werden?

Header-Datei

#include <atomic> 
#include <condition_variable> 
#include <mutex> 
#include <thread> 
#include <queue> 

#include "Error.h" 
#include "TypeDefinitions.h" 


struct Progress 
{ 
    StateDescription State; 
    uint8 ProgressPercentage; 
}; 

class ProgressIsolator 
{ 
public: 
    ProgressIsolator(); 
    virtual ~ProgressIsolator(); 

    void ReportProgress(const Progress& progress); 
    void Finish(); 

private: 
    std::atomic<bool> shutdown; 
    std::condition_variable itemAvailable; 
    std::mutex mutex; 
    std::queue<Progress> queue; 
    std::thread worker; 

    void Work(); 
}; 

CPP-Datei

#include "ProgressIsolator.h" 

ProgressIsolator::ProgressIsolator() : 
    shutdown(false), 
    itemAvailable(), 
    worker([this]{ Work(); }), 
    progressCallback(progressCallback), 
    completedCallback(completedCallback) 
{ 
    // TODO: only continue when worker thread is ready and listening? 
} 

ProgressIsolator::~ProgressIsolator() 
{ 
    Finish(); 
    worker.join(); 
} 

void ProgressIsolator::ReportProgress(const Progress& progress) 
{ 
    std::unique_lock<std::mutex> lock(mutex); 
    queue.push(progress); 
    itemAvailable.notify_one(); 
} 

void ProgressIsolator::Finish() 
{ 
    shutdown = true; 
    itemAvailable.notify_one(); 
} 

void ProgressIsolator::Work() 
{ 
    std::unique_lock<std::mutex> lock(mutex); 

    while (!shutdown) 
    { 
     itemAvailable.wait(lock); 
     while (!queue.empty()) 
     { 
      Progress progress = queue.front(); 
      queue.pop(); 
      // Do lengthy operation with progress 
     } 
    } 
} 

Antwort

0
void ProgressIsolator::Work() 
{ 
    while (!shutdown) 
    { 
     Progress progress; 
     { 
      std::unique_lock<std::mutex> lock(mutex); 
      itemAvailable.wait(lock, [this] { return !queue.empty(); }); 
      progress = queue.front(); 
      queue.pop(); 
     } 
     // Do lengthy operation with progress 
    } 
} 
+0

ich sehen, wo Sie sich gerade bewegen, sondern dass die gleiche Funktionalität nicht geben. Wenn sich der Push befindet und mehr als ein Element in der Warteschlange ist und dann die Methode Finish aufgerufen wird, werden nicht alle Elemente geöffnet. Von etwas weiterem Lesen denke ich, dass das Warten eine Sperre benötigt, aber diese Sperre nur dazu da ist, die Zustandsvariable zu schützen, nicht um die Warteschlange zu schützen. –

Verwandte Themen