当前位置:  开发笔记 > 编程语言 > 正文

如何在多线程C++中拆除观察者关系?

如何解决《如何在多线程C++中拆除观察者关系?》经验,为你挑选了1个好方法。

我有一个主题,提供Subscribe(Observer*)Unsubscribe(Observer*)提供给客户.Subject在其自己的线程中运行(从中调用Notify()订阅的Observers),并且互斥锁保护其内部的Observers列表.

我希望客户端代码 - 我无法控制 - 能够在取消订阅后安全地删除Observer.怎么能实现这一目标?

持有互斥锁 - 甚至是递归的互斥锁 - 当我通知观察者时,由于死锁风险而无法选择.

我可以在Unsubscribe调用中标记要删除的观察者,并将其从主题线程中删除.然后,客户可以等待特殊的"安全删除"通知.这看起来很安全,但对客户来说很麻烦.

编辑

一些说明性代码如下.问题是如何防止在"运行时出现问题"注释时发生取消订阅.然后我可以回拨一个已删除的对象.或者,如果我持有互斥锁而不是制作副本,我可以使某些客户端死锁.

#include 
#include 
#include 
#include 

using namespace std;
using namespace boost;

class Observer
{
public:
    void Notify() {}
};

class Subject
{
public:
    Subject() : t(bind(&Subject::Run, this))
    {
    }

    void Subscribe(Observer* o)
    {
        mutex::scoped_lock l(m);
        observers.insert(o);
    }

    void Unsubscribe(Observer* o)
    {
        mutex::scoped_lock l(m);
        observers.erase(o);
    }

    void Run()
    {
        for (;;)
        {
            WaitForSomethingInterestingToHappen();
            set notifyList;
            {
                mutex::scoped_lock l(m);
                notifyList = observers;
            }
            // Problem here
            for_each(notifyList.begin(), notifyList.end(), 
                     mem_fun(&Observer::Notify));
        }
    }

private:
    set observers;
    thread t;
    mutex m;
};

编辑

由于死锁风险,我无法在持有互斥锁时通知观察者.这种情况最明显的方式 - 客户端从Notify内部调用Subscribe或Unsubscribe - 可以通过使互斥锁递归来轻松解决.更隐蔽的是不同线程上间歇性死锁的风险.

我处于多线程环境中,因此在线程执行的任何时候,它通常都会保存一系列锁L1,L2,... Ln.另一个线程将保持锁K1,K2,... Km.正确编写的客户端将确保不同的线程始终以相同的顺序获取锁.但是当客户端与我的Subject的互斥体交互时 - 称之为X - 这个策略将被破坏:调用订阅/取消订阅以L1,L2,... Ln,X的顺序获取锁定.从我的主题线程调用通知获取锁定X,K1,K2,... Km的顺序.如果Li或Kj中​​的任何一个可以在任何呼叫路径上重合,则客户端会遇到间歇性死锁,几乎没有调试它的可能性.由于我不控制客户端代码,我不能这样做.



1> Rob K..:

Unsubscribe()应该是同步的,因此在Observer被保证不再在Subject列表中之前它不会返回.这是安全地做到这一点的唯一方法.

ETA(将我的评论转移到答案):

由于时间似乎不是问题,因此在通知每个观察者之间取出并释放互斥锁.您将无法以现在的方式使用for_each,并且您必须检查迭代器以确保它仍然有效.

for ( ... )
{
    take mutex
    check iterator validity
    notify
    release mutex
}

这将做你想要的.

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有