C++ 线程间的实时数据共享

C++ 线程间的实时数据共享,c++,multithreading,mutex,sharing,C++,Multithreading,Mutex,Sharing,对于嵌入式系统项目,我必须处理并发发送大量数据的传感器。目前,每个传感器都有自己的线程,许多线程相互引用 使用互斥锁,这些线程相互获取数据。但是,在生产过程中,一些线程无限期地等待另一个线程完成锁定数据的处理。我知道这个问题与死锁有关,但我发现这些问题很难发现和预防 我希望避免如此广泛地使用互斥体,因为它们会导致我的大部分难以复制的问题。我尝试过很多方法,比如在互斥对象超出范围时自动解锁,但到目前为止没有任何效果。 我有一个SharedData类,它包含以下方法: ``` template<

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

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

我希望避免如此广泛地使用互斥体,因为它们会导致我的大部分难以复制的问题。我尝试过很多方法,比如在互斥对象超出范围时自动解锁,但到目前为止没有任何效果。 我有一个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;
}
```

此处motor_sensor是对不同线程的引用,connected_是SharedData类型。

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


例如,队列从。

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


例如,

中的队列,如果您的程序设计方式使任何线程都不会在已经持有第一个锁定的互斥锁的情况下尝试锁定第二个互斥锁,那么您的程序将保证永远不会死锁

如果您不能做到这一点,您仍然可以保证您的程序不会死锁,如果您确保每当任何线程试图一次锁定多个互斥体时,它都会尝试以与其他线程尝试锁定互斥体相同的顺序锁定这两个(或多个)互斥体。(也就是说,只有当线程1执行一个
锁(互斥锁a);锁(互斥锁b)
而线程2执行一个
锁(互斥锁b);锁(互斥锁a)
时,才有可能出现死锁,因此最终会发生死锁)

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

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


除此之外,您可以始终使用一个
printf()
来插入每个锁定/解锁命令,该命令包括线程ID和互斥体的唯一标识符(例如,其内存位置),然后检查结果日志输出,以搜索输出中不一致的锁定模式。如果手动执行此日志解析变得太困难,则可以使用工具自动执行此日志解析。

如果程序的设计方式使线程在已经持有第一个锁定的互斥体时从未尝试锁定第二个互斥体,则程序将保证永远不会死锁

如果您不能做到这一点,您仍然可以保证您的程序不会死锁,如果您确保每当任何线程试图一次锁定多个互斥体时,它都会尝试以与其他线程尝试锁定互斥体相同的顺序锁定这两个(或多个)互斥体。(也就是说,只有当线程1执行一个
锁(互斥锁a);锁(互斥锁b)
而线程2执行一个
锁(互斥锁b);锁(互斥锁a)
时,才有可能出现死锁,因此最终会发生死锁)

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

如果,OTOH,您的程序已经太大/太复杂,无法进行重新设计,那么您的另一个选择是分析和调试程序死锁的原因,并提出必要的更改以避免这些死锁。valgrind之类的工具可以帮助实现这一点,在运行时自动检测不一致的互斥锁并告诉您。此外,如果您可以使程序进入死锁状态,调试器可以向您显示每个线程被阻塞的位置,以及该ca
void MotorMessage::SetConnectedModules(MotorSensor &motor_sensor) {
  out_buffer_[index_++] = motor_sensor.connected_.Get();
}