Многопоточность и общий ресурс: периодически копируйте данные из буфера (структура данных) в файл, используя C++

Мой код имеет структуру данных, скажем, например, "вектор vecor строк". У меня есть 2 потока:

THread 1 записывает данные в эту структуру данных (буфер в RAM).

Параллельно работающий поток 2, который должен копировать данные из вышеприведенного буфера, т.е. структуру данных, в файл за каждые "х" миллисекунд.

Мне интересно, как бы я достиг этого в C++? Следует учитывать ключевые моменты в постановке задачи, такие как:

a) Копирование из буфера в файл должно происходить только один раз за "X" миллисекунд.

б) Синхронизация между обоими потоками.

РЕДАКТИРОВАНИЕ ЗАПРОСА С БОЛЕЕ ДЕТАЛЯМИ НА СПРОС

Я хочу создать библиотеку (*.lib), и эта библиотека предоставляет некоторые API, следовательно, она получает входные данные из EXE или любого объекта, который использует мою библиотеку через эти API. Скажем, данные, полученные моей библиотекой, представлены в виде вектора строк.

FillLibraryDataStructure(std::vector<std::string>); // is the API of this library. Any app can call this API & pass a vector of string to this library.

Example app code:
for(int i=100; i<100;i))
{
std::vector<std::string> vec = GetVectorOfString(); // GetVectorOfString from business logic
FillLibraryDataStructure(vec);
}

Код библиотеки имеет общий ресурс:

    // Within library I've a 2D vector i.e. vector of vector of
 strings where all the vector of strings passed by application to this librray are added as a new row in vecofvecofstr.

ОБЩИЙ РЕСУРС:

std::vector<std::vector<string>> vecofvecofstr;

THREAD 1: копирует данные, полученные из API, в структуру данных, т.е. вектор вектора строк.

vecofvecofstr.push_back(vec);

THREAD 2: копирует содержимое этого вектора вектора строки (который был записан в 1-м потоке) в файлы (XML, HTML и т. Д.) За каждые "X" милисекунд.

Еще несколько замечаний о потоке 1: 1) Поток 1 должен работать непрерывно, т. Е. Когда приложение вызывает API, полученные данные должны быть помещены в структуру данных vecofvecofstr. 2) Через миллисекунды "X" копирования данных в буфер, 2-й поток должен начать работу и скопировать все содержимое, которое было выгружено в буфер до даты. Опять после тысячелетий "X" поток 2 должен остановиться и ждать "X" мс.

Как мне этого добиться. Здесь 1-й поток - это поток по умолчанию, в котором будет выполняться код моей библиотеки. Как мне добиться этого с помощью C++?

2 ответа

Вы могли бы использовать std::mutex а также std::condition_variable> в ваших интересах. И двойной буфер будет держать блокировку до минимума.

std::condition_variable> является ближайшей вещью к событию, которое может предложить стандартное устройство, его использование немного надумано, но оно работает.

В приведенном ниже примере используется двойной буфер, поэтому вы можете продолжать буферизацию данных, пока поток 2 сохраняет данные в файл, без блокировки.

Переменная std:condition_variable используется для того, чтобы ваше приложение могло выйти без ожидания. Это необходимо только в том случае, если вы хотите, чтобы приложение быстро завершалось, иначе вы можете использовать таймер. Призыв к notify_all() предотвратит тайм-аут wait_for() и немедленно разбудит поток записи, чтобы он мог завершиться без ожидания истечения времени ожидания. См. Ссылку по адресу: http://en.cppreference.com/w/cpp/thread/condition_variable

Заголовок:

#include <mutex>

// a generic double buffer
template<typename _Data>
class DoubleBuffer
{
private:
   std::mutex mutex_;

   std::vector<std::vector<_Data>> storeBuffer_;
   std::vector<std::vector<_Data>> saveBuffer_;

public:
   void lock() { mutex_.lock(); }
   void unlock() { mutex_.unlock();}

   auto& GetStoreBuffer() { return storeBuffer_; }
   auto& GetSaveBuffer()  { return saveBuffer_; }
   auto& Swap()
   {
     std::lock_guard<std::mutex> lock(mutex_);
     std::swap(storeBuffer_, saveBuffer_);
   }
};

В вашей библиотеке:

#include <condition_variable>
#include <thread>
#include <chrono>
#include <mutex>
#include <vector>
#include <string>

// As an example, could be inside a class, or struct 
static std::condition_variable exiting;
static std::mutex lk_exiting;

static DoubleBuffer<std::string> yourBuffer;

void FillLibraryDataStructure(std::vector<std::string> strings)
{
    // the lock is only for the duration of a swap - very short at worst.
    std::lock_guard<DoubleBuffer<std::string>> lock(yourBuffer);
    yourBuffer.GetStoreBuffer().emplace_back(strings);
}

void StoreLoop()
{
    for(;;)
    {
       {   // wait_for() unlocks lk_exiting, doc says lock should
           // be set before cv is triggered.
           std::unique_lock<std::mutex> lk_exiting;
           if (std::cv_status::no_timeout == exiting.wait_for(lk_exiting, 60s))
               break;  // app is exiting
       }

      yourBuffer.Swap();

      auto& stringsToSave = GetSaveBuffer();
      // save...  You do have plenty of time.
    }
}

// as an example.  A destructor would be a good place for this
void Exit_Application() 
{
  // stops the wait_for operation in StoreLoop()
  exiting.notify_all();
}

В качестве общего ответа на ваш общий вопрос, есть два возможных варианта:

1 - использовать некоторое время ожидания, сигнальные команды для сна и пробуждения потоков параллельно

2- использовать немного сна, чтобы обеспечить X миллисекунд в потоке чтения

Если вам нужен лучший ответ, дайте больше деталей

Другие вопросы по тегам