1

我想知道以下代码是否安全,因为信号可能由不同的线程触发:

using IntSignal = boost::signals2::signal<void(int)>;

class Foo
{
public:

  Foo(IntSignal& signal)
    : some_resource(new int(0))
  {
    scoped_connection = signal.connect([this](int i) { some_action(i); });
  }

  ~Foo()
  {
    delete some_resource;
  }

private:

  void some_action(int i)
  {
    *some_resource = i;
  }

  int* some_resource;

  boost::signals2::scoped_connection scoped_connection;
}

编辑:添加了一个虚构的资源、析构函数和一个实现,some_action以使其更清晰。带着这个问题,我想澄清一下我的假设是否正确,即信号槽可能在 ' 析构函数之后Foo但在scoped_connection' 析构函数之前调用。为简洁起见,我省略了互斥锁保护some_resource,但是,它与问题无关。

虽然当实例被销毁时连接会被断开,但在自己的析构函数调用和's 成员的销毁Foo之间可能存在微小的差距。如果资源在被破坏后被使用,这可能会更成问题。FooFoosome_action

我应该使用普通连接并在Foo's 的析构函数中断开它们吗?将scoped_connection成员作为类的最后一个成员(应该首先被销毁)并省略任何销毁逻辑是否安全?

4

1 回答 1

1

Foo你是对的,如果在信号运行和访问时调用 ' 的析构函数,则可能存在竞争some_resource

一个安全的解决方案是延长Foo插槽运行时的寿命:

class Foo : public std::enable_shared_from_this<Foo>
{
public:

  Foo(IntSignal& signal)
    : some_resource(new int(0))
  {        
      // moved connection initialization to a method since weak_from_this will  
      // be empty inside the constructor. It is initialized only afterwards.
      // It also make sense to connect your signal only after object
      // is fully initialized
  }

  void InitConnection()
  {
     auto weak_self = weak_from_this(); 
     scoped_connection = signal.connect(
       [weak_self](int i) 
      { 
         if (auto self = weak_self.lock())
         {
            // we managed to promote weak_self to a shared_ptr, 'this' will be alive 
            // as long as this scope lives
            some_action(i); // safe
         }
      });

  }

  ~Foo()
  {
     // will only be invoked after Foo's reference count drops to zero.
     // not during the signal is emitted
     delete some_resource; 
  }

private:    
  void some_action(int i)
  {
    *some_resource = i;
  }

  int* some_resource;    
  boost::signals2::scoped_connection scoped_connection;
}

笔记:

  1. enable_shared_from_this initializes a weak_ptr to 'this'. It is a great tool for the situation you described. See more here.
  2. Make sure you create Foo as a shared_ptr, otherwise weak_from_this will not work. Remember: Foo is shared between 2 threads.
于 2020-12-27T22:53:38.187 回答