线程之间的实时数据共享

时间:2018-10-08 14:36:43

标签: c++ multithreading mutex sharing

对于嵌入式系统项目,我必须处理同时发送大量数据的传感器。目前,每个传感器都有自己的线程,许多线程相互引用。

使用互斥锁,这些线程彼此获取数据。但是,在生产过程中,某些线程会无限期地等待另一个线程来完成对锁定数据的处理。我知道这个问题与死锁有关,但是我发现这些问题很难发现和避免。

我想避免广泛使用互斥锁,因为它们会导致我大多数难以重现的问题。我尝试了很多事情,例如当互斥锁超出范围时自动将其解锁,但是到目前为止,仍然没有任何效果。 我有一个SharedData类,其中包含以下方法:

```
template<class T>
T SharedData<T>::Get() {
  LockGuard lock(mutex_);
  T data = data_;
  if (!IsValid() && has_default_value_) {
    data = default_value_;
  }

  return data;
}

template<class T>
void SharedData<T>::Set(T data) {
  is_set_ = true;
  set_time_ = system_clock::now();

  LockGuard lock(mutex_);
  data_ = data;
}
```

我的问题如下:在线程之间共享实时数据的最佳,安全的方法是什么(最好不使用互斥锁)?

我正在寻找在线程之间传递消息的方向的解决方案。我还没有找到一种优雅的方法。

谢谢!

编辑:澄清“线程从彼此获取数据”,这是一个代码段:

void MotorMessage::SetConnectedModules(MotorSensor &motor_sensor) {
  out_buffer_[index_++] = motor_sensor.connected_.Get();
}

这里motor_sensor是对其他线程的引用,connected_是SharedData类型。

2 个答案:

答案 0 :(得分:4)

您可以设置一个或多个从传感器线程到使用者的原子队列。这样,您不必自己进行任何锁定。

例如,来自Intel TBB的队列。

答案 1 :(得分:0)

如果您以这样一种方式设计程序,即没有线程在已经持有第一个锁定的互斥锁的情况下尝试锁定第二个互斥锁,那么您的程序将永远不会死锁。

如果您无法管理该操作,则可以确保程序永远不会死锁,前提是您确保只要任何线程一次尝试锁定一个以上的互斥锁,就会尝试锁定这两个(或多个)互斥锁。 (以其他线程尝试将其锁定的顺序相同。(即,仅当线程#1执行lock(mutex_a); lock(mutex_b);而线程#2执行lock(mutex_b); lock(mutex_a);时,才可能出现死锁) -,因此最终会-发生)

关于如何执行此操作,如果您的程序足够小以至于可以重新设计它,那么可以使用的一种好的设计是线程之间的消息传递而不是共享数据。也就是说,如果线程A具有线程B需要了解的一些数据,则线程A应该将该数据包装在某种消息/事件对象中,并将该对象发布到消息/事件队列中,线程B将收到有关该消息/事件的通知。并稍后检查。 (由于A的事件发布或B的事件接收都不会阻塞一小段/有限的时间,因此通过这种方法避免了出现死锁的所有可能性)请注意,即使您要传递的数据量跨线程很大,如果通过shared_ptr而不是通过复制数据来传递数据,则此技术仍然有效。

如果是OTOH,您的程序已经太大/太复杂而无法进行重新设计,那么您的另一选择是分析和调试您的程序死锁的原因,并提出必要的更改以避免这些死锁。诸如valgrind的helgrind之类的工具可以通过在运行时自动检测不一致的互斥锁并将其告知您来提供帮助。同样,如果您可以使程序进入死锁状态,则调试器可以向您显示每个线程被阻塞的位置,这可以使您了解代码库中不一致的锁定顺序是什么导致死锁发生。

简短地说,您始终可以使用printf()来为每个锁定/解锁命令进行检测,其中{{1}}包括线程ID和互斥量的唯一标识符(例如,其内存位置),然后遍历结果日志-output在输出中搜索不一致的锁定模式。如果很难手动进行日志解析,则可以使用该工具进行自动化。