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

C++ C++/Boost:跨多个方法(getter)调用同步对资源的访问,c++,boost,locking,C++,Boost,Locking,我不确定这是否是一个关于编程技术或设计的问题,但我愿意听取建议 问题是:我想在数据源(传感器)和消费者之间创建一个抽象层。其思想是消费者只“知道”不同传感器类型的接口(抽象基类)。每种传感器类型通常由几个单独的值组成,这些值都有各自的getter方法 作为一个例子,我将使用一个简化的GPS传感器 class IGpsSensor { public: virtual float getLongitude() = 0; virtual float getLa

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

问题是:我想在数据源(传感器)和消费者之间创建一个抽象层。其思想是消费者只“知道”不同传感器类型的接口(抽象基类)。每种传感器类型通常由几个单独的值组成,这些值都有各自的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已经同步,因此必须使用递归互斥。然而,我假设有多个读卡器,但只有一个写卡器,因此我更愿意在这里使用共享互斥


感谢您的帮助。

可能的解决方案:从

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,您将无法在事务中调用它们。(除非将互斥锁配置为递归,否则只能锁定一次。)

公开“读卡器”接口如何?要获取reader对象,可以执行以下操作:

const IGpsSensorReader& gps_reader = gps_sensor.getReader();
{ //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
IGpsSensor类可以访问IGpsSensor类的受保护成员。建造时,它将获得锁。一旦破坏,它将释放锁。访问器可以执行以下操作:

const IGpsSensorReader& gps_reader = gps_sensor.getReader();
{ //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

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

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

谢谢你的主意。我认为,这本质上与“分发”互斥体本身相同,但对于互斥体,消费者可以使用类似于boost的scoped_lock的东西来获得锁RAII样式。正如我在最初的帖子中所说,递归锁的需要会阻止使用共享锁进行多读/单写访问。我认为你太抽象了。我们无法为Value1、Value2和Value3设计接口,其中一些可能偶尔有连接。如果中间层(代理)要有用,它必须知道何时以及如何使用。我编辑了原始文章,使其不那么抽象。这些值之间有联系,但代理不知道消费者真正需要哪些值。我喜欢读者界面的想法。然而,我正在努力实现。为了使示例正常工作,getReader()必须按值返回IGpsSensorReader(以创建一个临时引用,该引用将在以后销毁读取器)。但是因为它是一个不应该工作的接口。但也许我这里遗漏了什么……返回共享的ptr如何?或者IGpsSensorReader可以使用IGpsSensor参考:
IGpsSensorReader阅读器(gps传感器);//锁定传感器常数float fLongitude=reader.getLongitude()