【问题标题】:How to Create Thread-Safe Buffers / POD?如何创建线程安全缓冲区/POD?
【发布时间】:2015-05-11 00:41:05
【问题描述】:

我想我的问题很常见,但它让我发疯:

我有一个具有 5 个线程的多线程应用程序。其中 4 个线程完成它们的工作,例如网络通信和本地文件系统访问,然后将它们的输出全部写入这种形式的数据结构中:

struct Buffer {
  std::vector<std::string> lines;
  bool has_been_modified;
}

第 5 个线程将这些缓冲区/结构打印到屏幕上:

Buffer buf1, buf2, buf3, buf4;

...

if ( buf1.has_been_modified || 
     buf2.has_been_modified || 
     buf3.has_been_modified || 
     buf4.has_been_modified )
{
  redraw_screen_from_buffers();
}

如何防止缓冲区在被读取或写入时被覆盖?

我找不到合适的解决方案,尽管我认为这必须是一个安静的常见问题。

谢谢。

【问题讨论】:

  • 使用mutexes
  • 感谢您的回复。我在多线程方面不是很有经验。你能举个简短的例子吗?
  • 您要求购买 POD 有什么特别的原因吗? (注意当前接受的答案没有描述 POD)
  • 是的,我不想用 getter 和 setter 围绕我的 struct 建立一个大类。还调用我的struct 缓冲区对我来说似乎不是 100% 正确,所以我添加了 POD。

标签: c++ multithreading c++11


【解决方案1】:

您应该使用互斥锁。互斥类是std::mutex。使用 C++11,您可以使用 std::lock_guard&lt;std::mutex&gt; 使用 RAII 封装互斥锁。因此,您可以将 Buffer 结构更改为

struct Buffer {
   std::vector<std::string> lines;
   bool has_been_modified;
   std::mutex mutex;
};

无论何时你读取或写入缓冲区或has_been_modified,你都会这样做

std::lock_guard<std::mutex> lockGuard(Buffer.mutex); //Do this for each buffer you want to access
... //Access buffer here

并且互斥体在销毁时会被lock_guard自动释放。

您可以阅读有关互斥锁的更多信息here

【讨论】:

  • 谢谢!这就是我需要的!
  • @user4832939 - 虽然您明确要求使用互斥锁,但您所描述的情况似乎是条件变量的有效用例。详情请查看 Schultz9999 的答案。
  • 咳咳:读取或修改缓冲区,或 has_been_modified 布尔值。不仅仅是修改。 (更具体地说,如果其他线程可能与读取同时写入,您还需要锁定读取)查看竞争条件的定义。
  • @AndreCostur 好收获!固定。
【解决方案2】:

您可以在缓冲区周围使用互斥体(或多个互斥体),以确保它们不会被多个线程同时修改。

// Mutex shared between the multiple threads
std::mutex g_BufferMutex;

void redraw_screen_from_buffers()
{
   std::lock_guard<std::mutex> bufferLockGuard(g_BufferMutex);
   //redraw here after mutex has been locked.
}

那么当缓冲区被修改时,你的缓冲区修改代码将不得不锁定同一个互斥体。

void updateBuffer()
{
   std::lock_guard<std::mutex> bufferLockGuard(g_BufferMutex);
   // update here after mutex has been locked
}

This 包含一些互斥体示例。

【讨论】:

  • 不好,因为这意味着一次修改的缓冲区不超过一个
  • @Krab 然后对每个缓冲区使用一个互斥锁,redraw_screen_from_buffers 函数在重绘之前锁定所有互斥锁。
【解决方案3】:

您想要完成的似乎是拥有多个线程/工作者和一个观察者。后者仅在所有工作人员都完成/发出信号时才需要完成其工作。如果是这种情况,请检查此 SO q/a 中的代码。 std::condition_variable - Wait for several threads to notify observer

【讨论】:

    【解决方案4】:

    mutex 在避免数据竞争时是一件非常好的事情,我相信@Phantom 发布的答案会让大多数人满意。但是,应该知道这不能扩展到大型系统。

    通过锁定您正在同步您的线程。由于一次只能访问一个向量,因此在写入容器的线程上将导致另一个等待它完成......这可能对您有好处,但在需要高性能时会导致严重的性能瓶颈。

    最好的解决方案是使用更复杂的无锁结构。不幸的是,我认为 STL 中没有任何标准的无锁结构。一个无锁队列的例子是可用的here

    使用这样的结构,您的 4 个工作线程将能够将消息排入容器,而第 5 个工作线程会将它们出列,而无需任何数据争用

    More on lockfree datastructure can be found here !

    【讨论】:

      猜你喜欢
      • 2016-12-26
      • 2012-09-04
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多