多线程&共享资源:使用C ++定期将数据从缓冲区(数据结构)复制到文件

时间:2017-07-03 14:53:39

标签: c++ timer synchronization c++14 mutex

我的代码有一个数据结构,例如"字符串的vecor矢量。我有2个主题:

THRE 1正在向此数据结构(RAM中的缓冲区)写入数据。

并行运行的线程2应该将数据从上面的缓冲区复制,即数据结构到每个" x"毫秒。

  

我想知道如何在C ++中实现这一目标?它应该考虑关键   问题陈述中的要点如下:

     

a)从缓冲区到文件的副本只能在" X"   毫秒。

     

b)两个线程之间的同步。

根据问题更详细地编辑查询

我想构建一个库(* .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:将此向量的字符串(在第一个线程中写入)的内容复制到文件(XML,HTML等)。 对于每一个&#34; X&#34; miiliseconds

  

关于thread1的更多要点:1)线程1应该正在运行   连续地,即当应用程序调用API数据时   收到的应该放到数据结构vecofvecofstr。 2)之后   &#34; X&#34;将数据复制到缓冲区的二恶习,第二个线程应该   开始&amp;它应该复制所有转储到缓冲区的东西   直到约会。再次&#34; X&#34; milisonds线程2应暂停&amp;等待   为&#34; X&#34;毫秒。

我如何实现这一目标。这里第一个线程是我的库代码将在其中运行的默认线程。 我如何使用C ++实现这一目标?

2 个答案:

答案 0 :(得分:0)

作为对一般问题的一般回答,有两种可能的选择:

1-使用一些等待,信号命令来休眠和并行唤醒线程

2-使用一些睡眠来提供读取线程

的X毫秒

如果您需要更好的答案,请提供更多详情

答案 1 :(得分:0)

您可以使用std::mutexstd::condition_variable>。并且双缓冲区可以将锁定保持在最低限度。

std::condition_variable>是与std必须提供的事件最接近的事情,它的使用有点人为,但它有效。

下面的示例使用双缓冲区,因此您可以在线程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();
}