Общение через очередь данных.При желании очередь может иметь максимальный размер.
Один поток генерирует данные и помещает их в очередь.
Другой поток извлекает данные из очереди и обрабатывает их.
Когда очередь пуста, потребляющий поток ожидает в очереди новых данных для отправки.
Когда очередь заполнена, производящий поток ожидает в очереди данных, которые будут извлечены.Кроме того, вы можете отбросить и заменить ожидающие данные в очереди.Зависит от того, на что похожа ваша модель данных (важна последняя или важна вся последовательность)
Простая очередь:
template<class T>
struct threadsafe_queue {
T pop() {
auto l = lock();
cv.wait( l, [&]{ return !data.empty(); } );
T r = std::move(data.front());
data.pop_front();
return r;
}
void push( T&& t ) {
auto l = lock();
data.push_back( std::move(t) );
cv.notify_one();
}
void abandon() {
auto l = lock();
data = {};
}
private:
std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(m); }
std::mutex m;
std::condition_variable cv;
std::deque<T> data;
};
одна с ограничением на количество записей должнаиметь вторую условную переменную condition_variable, чтобы уведомлять, когда кто-то появляется, и push должен видеть, достигли ли вы предела.
Поддержка "перезаписать при заполнении" становится другой опцией.1-элементный «самый последний» выглядит так:
template<class T>
struct mono_threadsafe_queue {
// waits until we have data, then returns it.
T pop() {
auto l = lock();
cv_hasdata.wait( l, [&]{ return (bool)data; } );
T r = std::move(*data);
data = boost::none;
cv_hasroom.notify_one();
return r;
}
// waits for there to be room if there is none.
void push( T&& t ) {
auto l = lock();
cv_hasroom.wait( l, [&]{ return !(bool)data; } );
data = std::move(t);
cv_hasdata.notify_one();
}
void replace( T&& t ) {
auto l = lock();
data = std::move(t);
cv_hasdata.notify_one();
}
// replaces data if f returns true, or if there is no data
// imagine data with a timestamp, and we only want to replace it with
// newer data
template<class F>
void replace_if( T&& t, F&& f ) {
auto l = lock();
if (!data || !f(*data))
{
data = std::move(t);
cv_hasdata.notify_one();
}
}
void abandon() {
auto l = lock();
data = boost::none;
cv_hasroom.notify_one();
}
private:
std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(m); }
std::mutex m;
std::condition_variable cv_hasdata;
std::condition_variable cv_hasroom;
boost::optional<T> data;
};