加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

使用C中的非虚拟公共接口和Scoped锁来避免死锁

发布时间:2020-12-16 10:38:26 所属栏目:百科 来源:网络整理
导读:我遇到了一个让我感到不安的问题.似乎我发现了一种容易解决的情况,但如果a)我在编程时失去了注意力,或者b)其他人开始实现我的界面并且不知道如何处理,这可能会导致问题这个情况. 这是我的基本设置: 我有一个抽象类,我正在使用它作为几种数据类型的通用接口.
我遇到了一个让我感到不安的问题.似乎我发现了一种容易解决的情况,但如果a)我在编程时失去了注意力,或者b)其他人开始实现我的界面并且不知道如何处理,这可能会导致问题这个情况.

这是我的基本设置:

我有一个抽象类,我正在使用它作为几种数据类型的通用接口.我采用了非虚拟公共接口范例(Sutter,2001)以及范围锁定来提供一些线程安全性.一个示例接口类看起来像这样(我省略了有关作用域锁定和互斥锁实现的细节,因为我不认为它们是相关的):

class Foo
{
public:
    A( )
    {
        ScopedLock lock( mutex );
        aImp( );
    }
    B( )
    {
        ScopedLock lock( mutex );
        bImp( );
    }
protected:
    aImp( ) = 0;
    bImp( ) = 0;
}

然后由用户来实现aImp和bImp,这就是问题所在.如果aImp执行一些使用bImp的操作,那么执行此操作非常容易(在某种意义上几乎是逻辑的):

class Bar
{
protected:
    aImp( )
    {
        ...
        B( );
        ...
    }
    bImp( )
    {
        ...
    }
}

僵局.当然,对此的简单解决方案是始终调用受保护的虚拟函数而不是其公共变体(在上面的代码段中用bImp()替换B()).但是,如果我犯了错误,或者更糟糕的是让其他人自己上吊,那么自己挂起来似乎仍然很容易.

有没有人有办法试图阻止抽象类的实现者在编译时调用那些公共函数,或者有助于避免死锁解决方案?

只是为了踢,一些互斥体允许操作,这将避免死锁问题.例如,如果我使用Windows函数EnterCriticalSection和LeaveCriticalSection实现它,则没有问题.但我宁愿避免使用特定于平台的功能.我目前在我的作用域锁实现中使用boost :: mutex和boost :: shared_mutex,据我所知,它并不试图避免死锁(我认为我几乎更喜欢).

解决方法

使用私有继承可能会解决您的问题:

class Foo
{
public:
  void A( )
    {
      ScopedLock lock( mutex );
      aImp( );
    }
  void B( )
    {
      ScopedLock lock( mutex );
      bImp( );
    }

protected:
  virtual void aImp( ) = 0;
  virtual void bImp( ) = 0;
};

class FooMiddle : private Foo
{
public:
  using Foo::aImp;
  using Foo::bImp;
};

class Bar : public FooMiddle
{
  virtual void aImpl ()
  {
    bImp ();
    B ();                   // Compile error - B is private
  }
};

私有地从Foo派生,然后使用FooMiddle确保Bar无法访问A或B.但是,bar仍然可以覆盖aImp和bImp,而FooMiddle中的using声明意味着仍然可以从Bar调用它们.

或者,有助于但不能解决问题的选项是使用Pimpl模式.你最终得到的东西如下:

class FooImpl
{
public:
  virtual void aImp( ) = 0;
  virtual void bImp( ) = 0;
};

class Foo
{
public:
  void A( )
    {
      ScopedLock lock( mutex );
      m_impl->aImp( );
    }
  void B( )
    {
      ScopedLock lock( mutex );
      m_impl->bImp( );
    }

private:
  FooImpl * m_impl;
}

好处是在源自FooImpl的类中,它们不再具有“Foo”对象,因此不能轻易地调用“A”或“B”.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读