2016-10-18 8 views
0

У меня есть dll, которая имеет высокоприоритетные функции, которые работают в потоке с высоким приоритетом. Эта DLL должна сообщить о прогрессе. В основном используется система обратного вызова. Проблема в том, что dll не контролирует количество времени, которое должен выполнить обратный вызов для завершения. Это означает, что высокоприоритетные функции зависят от реализации обратного вызова, который неприемлем.Сделать область блокировки меньше в потоковом очереди

Идея состоит в том, чтобы иметь класс между ними, который буферизует уведомления о ходе и вызывает обратный вызов.

Я новичок в C++ 11, и это функция потоковой передачи и пытается найти возможности. У меня есть реализация, но у меня есть проблема (по крайней мере, тот, который я вижу сейчас). Когда поток оживает после ожидания мьютекса, он снова приобретается и остается до следующего ожидания. Это означает, что блокировка сохраняется до тех пор, пока продолжается продолжительная операция. Добавление прогресса будет заблокировано здесь. В основном много кода без выигрыша. Я подумал об изменении кода, но я не знаю, правильная ли это реализация.

 Progress progress = queue.front(); 
     queue.pop(); 
     lock.unlock(); 
     // Do lengthy operation with progress 
     lock.lock(); 

Я думаю, что мне нужно ждать переменную условия, но это не должно быть связано с блокировкой. Я не понимаю, как это можно сделать. Пропустить фиктивную блокировку и использовать другую блокировку для защиты очереди? Как эта проблема должна решаться в C++ 11?

заголовок файла

#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 файл

#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 
     } 
    } 
} 

ответ

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

Я вижу, где вы идете, но это не дает ту же функциональность. Если нажимается заголовок и в очереди находится более одного элемента, а затем вызывается метод Finish, это приведет к тому, что не будут выгружены все элементы. Из некоторого дальнейшего чтения я думаю, что ожидание требует блокировки, но блокировка существует только для защиты переменной условия, а не для защиты очереди. –