【问题标题】:Poco - using removeObserver safelyPoco - 安全地使用 removeObserver
【发布时间】:2015-08-25 04:18:54
【问题描述】:

我在 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刚刚returned from 在它被销毁后可能会被访问​​。

我的问题是:这是一个有效的问题吗?如果是,我应该怎么做才能确保在return 之后不会发生通知?

【问题讨论】:

    标签: c++ multithreading poco-libraries


    【解决方案1】:

    编辑:因为removeObserver()disabling 被移除的观察者,所以上面的代码是安全的。下面的答案留作记录,以便理解 cmets 部分。


    原答案:

    这是一个有效的问题 - 工作线程函数可以在 add/removeObserver() 调用之间被抢占。由于postNotification()makes a copy*在所有观察者的指针中,如果有多个来自其他线程的通知,在你调用removeObserver()(甚至函数返回后)。

    现在,无需担心函数返回后会访问观察者,因为它是由通知中心将cloned 转换为SharedPtr。然而,由于 NObserver 持有它的naked address,因此此时调用通知处理程序存在问题。为防止坏事发生,请在从函数返回之前调用 obs.disable() - 这将通过 disarm 以线程安全的方式处理任何待处理通知。


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

    【讨论】:

    • 对不起,我在哪里打电话disable()
    • event.wait() 之后的任何地方,最好尽快。
    • 你的意思是obs.disable() 那里?好的。您提到 NotificationCenter 获取观察者的副本,所以仍然会有机会在 NotificationCenter 中启动通知(可能当前通知另一个线程并且尚未到达该工作人员)并且已经拿了一个副本,所以它仍然会认为这个工人的观察者没有被禁用?
    • 是的,对不起,它是observer,而不是notifier.disable()。我会在答案中修复它。至于问题的第二部分,NObserver::disable/notify() 是受互斥体保护的,所以如果一个线程正在执行notify()disable() 会等待。
    • 好的,考虑到 mutex 应该可以正常工作。谢谢,我试试看
    猜你喜欢
    • 2012-12-04
    • 2021-07-04
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 2011-08-02
    相关资源
    最近更新 更多