我有一个问题,每次都在不同的主题中更新主题。因此,每当主题被更新时,它相应地用新信息更新观察者。但是,如果观察者列表很长,则需要一些时间来更新所有观察者。想想一个经常更新的主题。当主题正在更新观察者时,“主题”对象被锁定,因此不能由不同的线程更新。这将为主题创建信息流量或导致信息丢失。
您是否知道如何在多线程环境中处理这些问题?另外,有人可以推荐一些关于用C ++进行并行编程的书吗?
答案 0 :(得分:7)
考虑使用producer-consumer queues或message queues。对于您的示例,您可以通过两种方式使用队列:
对主题的更改已排队。当某些内容更新主题时,它会将新状态置于队列中并立即返回。这样,在通知观察者时,更新器不会阻塞。您将需要一个持续使状态更改出列并更新观察者的线程。
观察员的通知排队。每个观察者都有一个队列,其中发布了主题状态变化通知。
如果您使用的是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); } } } }