c++ /Boost:跨多个方法(getter)调用同步对资源的访问

C++/Boost: Synchronize access to a resource across multiple method (getter) calls

本文关键字:同步 调用 资源 访问 getter Boost 方法 c++      更新时间:2023-10-16

我不确定这是一个关于编程技术或设计的问题,但我愿意听取建议。

问题:我想在数据源(传感器)和消费者之间创建一个抽象层。其理念是消费者只"知道"不同传感器类型的接口(抽象基类)。每种传感器类型通常由几个单独的值组成,这些值都有自己的getter方法。

作为一个例子,我将使用一个简化的GPS传感器

class IGpsSensor {
    public:
        virtual float getLongitude() = 0;
        virtual float getLatitude() = 0;
        virtual float getElevation() = 0;
        // Deviations
        virtual float getLongitudeDev() = 0;
        virtual float getLatitudeDev() = 0;
        virtual float getElevationDev() = 0;
        virtual int getNumOfSatellites() = 0;
};

由于对传感器的更新是由不同的线程完成的(细节取决于接口的实现),同步getter和更新方法似乎是确保一致性的合理方法。

到目前为止一切顺利。在大多数情况下,这种级别的同步应该足够了。然而,有时可能需要获取多个值(使用连续的getXXX()调用),并确保其间不发生更新。这是否必要(以及哪些值是重要的)取决于消费者。

坚持这个例子,在很多情况下,只需要知道经度和纬度(但希望两者都与同一个update()相关)。我承认这可以通过将它们分组到一个"Position"类或结构中来实现。但消费者也可能将传感器用于更复杂的算法,也需要偏差。

现在我在想,什么是正确的方法来做到这一点。

我能想到的解决方案:

  • 将所有可能的值分组到一个结构体(或类)中,并添加一个额外的(同步的)getter,一次返回所有值的副本——在可能10个值中只需要2或3个的情况下,对我来说似乎是很多不必要的开销。

  • 添加一个方法返回对数据源中使用的互斥锁的引用,以允许消费者锁定——这感觉不像是"好的设计"。因为getter已经同步了,所以必须使用递归互斥锁。然而,我假设有多个读取器,但只有一个写入器,因此我宁愿在这里使用共享互斥。

谢谢你的帮助。

如何公开"Reader"接口?要获取阅读器对象,您可以这样做:

const IGpsSensorReader& gps_reader = gps_sensor.getReader();

IGpsSensorReader类可以访问IGpsSensor类的受保护成员。在构造时,它将获取锁。一旦被破坏,它就会释放锁。访问器可以这样做:

{ //block that accesses attributes
   const IGpsSensorReader& gps_reader = gps_sensor.getReader();
   //read whatever values from gps_reader it needs
} //closing the scope will destruct gps_reader, causing an unlock

您还可以向执行更新的线程公开getwwriter方法。在内部,您可以使用boost的shared_mutex来调解读写器之间的访问。

我在一些简单的项目中使用的一种技术是只提供对代理对象的访问。该代理对象在其生命周期内持有锁,并为我的数据提供实际接口。这种访问本身不进行同步,因为它只能通过已经适当锁定的代理来访问。我从未尝试过将其扩展到一个全面的项目,但它似乎对我的目的很有效。

可能的解决方案:从

派生所有的源类
class Transaction {
  pthread_mutex_t mtx;
  // constructor/destructor
public:
  void beginTransaction() { pthread_mutex_lock(&mtx); } // ERROR CHECKING MISSING
  void endTransaction() { pthread_mutex_unlock(&mtx); } // DO ERROR CHECKING
protected:
  // helper method
  int getSingle(int *ptr)
  { int v; beginTransaction(); v=*ptr; endTransaction(); return v; }
};

如果需要读取多个值,请使用begin/endTransaction方法。要定义getValue函数,只需调用getSingle,并带指针指向适当的成员[这只是一个方便的方法,这样您就不必在每个getValue函数中调用begin/endTransaction]。

您将需要充实一些细节,因为如果您的getValue函数使用begin/endTransaction,您将无法在事务中调用它们。(互斥锁只能锁定一次,除非它被配置为递归。)