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

时间:2011-07-03 16:50:31

标签: c++ boost locking

我不确定这是关于编程技巧或设计的问题,但我愿意接受建议。

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

作为一个例子,我将使用简化的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()调用)并确保两者之间不发生更新。这是否必要(以及哪些值很重要)取决于消费者。

坚持这个例子,在很多情况下,了解经度和纬度(但希望两者都与相同的更新()相关)非常重要。我承认可以将它们组合成一个“位置”类或结构。但消费者也可能将传感器用于更复杂的算法,并且也需要偏差。

现在我想知道,做这件事的正确方法是什么。

我能想到的解决方案:

  • 将所有可能的值分组到一个struct(或类)中,并添加一个额外的(synchronized)getter一次性返回所有值的副本 - 对于我来说似乎是很多不必要的开销,如果只有2或3个可能需要10个值。

  • 添加一个方法,返回对数据源中使用的互斥锁的引用,以允许消费者锁定 - 这不像“好设计”。由于getter已经同步,因此必须使用递归互斥锁。但是,我假设有多个读者,但只有一个作者,因此我宁愿在这里使用共享互斥锁。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

如何暴露“读者”界面?要获得读者对象,您可以这样做:

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

您还可以将getWriter方法公开给执行更新的线程。在内部,您可以使用boost的shared_mutex来调解读者和作者之间的访问。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

可能的解决方案:从

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