简体   繁体   English

C ++线程安全-在工作者和控制器之间交换数据

[英]C++ thread safety - exchange data between worker and controller

I still feel a bit unsafe about the topic and hope you folks can help me - 我对该主题仍然感到不安全,希望大家能帮助我-

For passing data (configuration or results) between a worker thread polling something and a controlling thread interested in the most recent data, I've ended up using more or less the following pattern repeatedly: 为了在轮询某些内容的工作线程与对最新数据感兴趣的控制线程之间传递数据(配置或结果),我最终或多或少地重复使用了以下模式:

Mutex m;
tData * stage;       // temporary, accessed concurrently

// send data, gives up ownership, receives old stage if any
tData * Send(tData * newData)
{
   ScopedLock lock(m);
   swap(newData, stage);              
   return newData;
}

// receiving thread fetches latest data here
tData * Fetch(tData * prev)
{
  ScopedLock lock(m);
  if (stage != 0)
  {
     // ... release prev
     prev = stage;
     stage = 0;
  }
  return prev;  // now current
}

Note: This is not supposed to be a full producer-consumer queue, only the msot recent data is relevant. 注意:这不应该是完整的生产者-消费者队列,只有msot最近数据是相关的。 Also, I've skimmed ressource management somewhat here. 另外,我在这里略略了资源管理。

When necessary I'm using two such stages: one to send config changes to the worker, and for sending back results. 必要时,我使用两个这样的阶段:一个将配置更改发送给工作程序,以及将结果发送回。

Now, my questions 现在,我的问题

assuming that ScopedLock implements a full memory barrier: 假设ScopedLock实现了完整的内存屏障:

  • do stage and/or workerData need to be volatile? 阶段和/或workerData是否需要可变?
  • is volatile necessary for tData members? tData成员需要volatile吗?
  • can I use smart pointers instead of the raw pointers - say boost::shared_ptr ? 我可以使用智能指针代替原始指针吗?比如boost::shared_ptr
  • Anything else that can go wrong? 还有什么可能出错吗?
  • I am basically trying to avoid "volatile infection" spreading into tData, and minimize lock contention (a lock free implementation seems possible, too). 我基本上是在尝试避免“易受感染”传播到tData中,并最小化锁争用(似乎也可以实现无锁实现)。 However, I'm not sure if this is the easiest solution. 但是,我不确定这是否是最简单的解决方案。

ScopedLock acts as a full memory barrier. ScopedLock充当完整的内存屏障。 Since all this is more or less platform dependent, let's say Visual C++ x86 or x64, though differences/notes for other platforms are welcome, too. 由于所有这些都或多或少地依赖于平台,因此可以说Visual C ++ x86或x64,尽管也欢迎其他平台的差异/说明。


(a prelimenary "thanks but" for recommending libraries such as Intel TBB - I am trying to understand the platform issues here) (对“ Intel TBB”之类的库的推荐,表示“感谢”,我想在这里理解平台问题)

You don't need volatile here. 您不需要在这里volatile Use volatile only if the value can change due to something outside of your program, such as if the variable represents a memory-mapped hardware register. 仅当值可能由于程序外部的原因而发生更改(例如,变量代表内存映射的硬件寄存器)时才使用volatile The values here are only modified inside your program, so you can trust the compiler to know when it can and can't cache the values. 此处的值仅在程序内部进行修改,因此您可以信任编译器知道何时以及何时不能缓存值。

If you need to make sure the worker and controller aren't accessing the shared data at the same time, I would recommend that you use a mutex instead. 如果您需要确保工作者和控制器不会同时访问共享数据,则建议您使用互斥锁 In both your Send and Fetch functions, simply lock the mutex, manipulate stage , and release the mutex. 在您的SendFetch功能中,只需锁定互斥锁,操作stage并释放互斥锁即可。 I don't know what system libraries you have available, but there's a good description of POSIX mutexes (from pthreads) here . 我不知道是什么系统库您有可用,但有POSIX互斥体(从并行线程)的一个很好的描述在这里 The Win32 version (albeit with less explanation) is available here . Win32版本(尽管解释较少)可在此处获得 Other libraries will use different names, but the concept is the same. 其他库将使用不同的名称,但是概念是相同的。

Well here's one problem: 好吧,这是一个问题:

Your send function needs to pass in newData by reference (or pointer to pointer). 您的send函数需要通过引用(或指向指针的指针)传递newData。 Otherwise the result of the swap never makes it back to the caller. 否则,交换的结果将永远不会返回给调用者。

You won't need volatile just means that the data is always read from memory everytime it's accessed. 您不需要volatile就意味着每次访问数据时总是从内存中读取数据。 Since your program is always changing the value of stage, the compiler will know whats going on and everything will be fine. 由于您的程序总是在更改stage的值,因此编译器将知道发生了什么,一切都会很好。 You only use volatile if you have something outside of your program changing the value. 仅当程序外有其他值更改时,才使用volatile。 Eg, you have a serial port that is sending data to a place in memory and you have your program polling that memory for updates. 例如,您有一个串行端口正在将数据发送到内存中的某个位置,并且您的程序正在轮询该内存以​​进行更新。 Every time you poll that memory, you have to check the memory, not the cache, and that's where you'd use volatile. 每次轮询该内存时,都必须检查内存,而不是缓存,这就是使用volatile的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM