多线程观察者模式

时间:2012-01-05 18:07:55

标签: c++ multithreading observer-pattern

我有一个问题,每次都在不同的主题中更新主题。因此,每当主题被更新时,它相应地用新信息更新观察者。但是,如果观察者列表很长,则需要一些时间来更新所有观察者。想想一个经常更新的主题。当主题正在更新观察者时,“主题”对象被锁定,因此不能由不同的线程更新。这将为主题创建信息流量或导致信息丢失。

您是否知道如何在多线程环境中处理这些问题?另外,有人可以推荐一些关于用C ++进行并行编程的书吗?

2 个答案:

答案 0 :(得分:7)

考虑使用producer-consumer queuesmessage queues。对于您的示例,您可以通过两种方式使用队列:

  1. 对主题的更改已排队。当某些内容更新主题时,它会将新状态置于队列中并立即返回。这样,在通知观察者时,更新器不会阻塞。您将需要一个持续使状态更改出列并更新观察者的线程。

  2. 观察员的通知排队。每个观察者都有一个队列,其中发布了主题状态变化通知。

  3. 如果您使用的是Qt库,则可以使用信号和放大器。具有Qt::QueuedConnection连接类型的插槽机制。插槽通过接收器的事件队列并在接收器的线程中执行。这样,当接收者执行各自的时隙时,发送者不会阻塞。

    您的计划可能是Actor model (paradigm)的合适人选。以下是一些实现actor模型的C ++库:

    您的计划也可能是Dataflow范例的良好候选人。查看提议的Boost Dataflow库,该库支持threading


    我没有推荐的书,但请查看Herb Sutter关于C ++并发的series of Dr Dobbs articles

答案 1 :(得分:1)

我用Java编写了一个多线程观察者模式


    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;

    /**
     * An observer pattern that allows listeners to register(), unregister() in
     * multiple threads and also notify listeners in another thread.
     * 
     * A HashMap keeps track of the listeners and their status (active, obsolete).
     * When a listener unregister, its entry is marked as obsolete in this map.
     * 
     * During firing of an event, the observer notifies all the listeners that are
     * active, the active status will be stored in a Boolean that's synchronized so
     * rare race conditions like calling notify on an active listener that has just
     * turned obsolete will not happen.
     * 
     * 
     */
    public class MultithreadedObserverPattern  {

        interface Handler {
            void handleEvent(T listener);
        }

        class BooleanHolder {
            boolean val;

            BooleanHolder(boolean v) {
                val = v;
            }

            void set(boolean v) {
                val = v;
            }

            boolean get() {
                return val;
            }
        }

        Map listeners = new HashMap();

        public void register(AbstractListener l) {
            synchronized (listeners) {
                listeners.put(l, new BooleanHolder(true));
            }
        }

        public void unregister(AbstractListener l) {
            synchronized (listeners) {
                BooleanHolder status = listeners.get(l);
                if (status != null) {
                    // notify call also syncing on status
                    synchronized (status) {
                        status.set(false);
                    }
                }
                // set to false
            }
        }

        public void notifyAll(Handler handler) {
            // here we do not synchroznie on listeners to avoid tricky lock situations
            // make a copy of the map
            List> activeListeners = new ArrayList>();
            List inactiveListeners = new ArrayList(); 

            synchronized (listeners) {
                for (Entry entry : listeners.entrySet()) {
                    if (entry.getValue().get()) {
                        activeListeners.add(entry);
                    } else {
                        inactiveListeners.add(entry.getKey());
                    }
                }
            }
             // call the method on active listener
            // 
            for (Entry e : activeListeners) {
                BooleanHolder status = e.getValue();
                // remove those listeners that are no longer active
                synchronized (status) {
                    if (status.get()) {
                          handler.handleEvent(e.getKey());
                    }
                }
            }

            synchronized (listeners) {
                // remove inactive listeners
                for (AbstractListener l : inactiveListeners) {
                    listeners.remove(l);
                }
            }
        }
    }