我在“ Activity ”线程中有一个通知中心:

Poco::NotificationCentre nc;   // publicly visible

// (thread main loop which will post notifications from time to time)

以及作用于通知的多个工作线程。但是,等待通知的那些线程可能也需要在外部随时发出信号以退出。所以我在工作线程中有以下内容(同样,为了清楚起见,这是伪代码,省略了一些细节)
Poco::Event event;
std::string s;
MyNotificationClass notifier{event, s};  // holds those by reference
Poco::NObserver<MyNotificationClass, MyNotification> obs(notifier, &MyNoficationClass::func);

nc.addObserver(obs);
event.wait();
nc.removeObserver(obs);

return s;

通知类为:
struct MyNotificationClass
{
    MyNotificationClass(Poco::Event &ev, std::string &s): ev(ev), s(s) {}
    void func(const Poco::AutoPtr<MyNotification> &p)
    {
        s = p->s;
        ev.set();
    }
    Poco::Event &ev;
    std::string &s;
};

我担心的是,即使在工作线程中调用了removeObserver之后,通知中心也可能已同时向其发布了通知,因此工作线程刚从中获得s的函数中的对象return可能会被访问在它被摧毁之后。

我的问题是:这是否是一个有效的问题,如果是这样,我应该怎么做才能确保在return之后不会出现任何通知?

最佳答案

编辑:由于removeObserver()disabling被移除的观察者,所以上面的代码是安全的。下面的答案留作记录,以使“注释”部分有意义。

原始答案:

这是一个有效的问题-辅助线程可以在add/removeObserver()调用之间被抢占。由于所有观察者的指针均为postNotification() makes a copy *,因此,如果有来自其他线程的多个通知,则指向您的观察者的指针可能仍在调用removeObserver()之后(甚至在函数返回之后)在一个或多个拷贝列表中。

现在,无需担心在函数返回后访问观察者,因为NotificationCenter将它从cloned转换为SharedPtr。但是,由于NObserver保留了它的naked address,因此担心在那时调用通知处理程序。为了防止发生不良情况,请在从函数返回之前调用obs.disable()-这将以线程安全的方式disarm对所有未决通知的通知处理。

*由于性能原因-我们不想在执行所有通知处理程序时阻塞其余的NotificationCenter。

10-06 03:32