3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

スレッドセーフでコールバック中にAdd/Removeしても大丈夫なListener Listのテンプレートクラス

Last updated at Posted at 2015-02-26
  • コールバック前にnumListenersを取得するのでAdd直後に通知が来ない
  • コールバック中にindexがずれないように、RemoveはNULLで置き換えるだけにしてコールバック後に一括消去
  • vector::iteratorはpush_backしたときに無効化されることがあるのでindexを使ってループする
ListenerList.h
#ifndef LISTENERLIST_H_
#define LISTENERLIST_H_

#include <vector>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>

template< class Listener >
class ListenerList
{
public:
	inline ListenerList() : mNumActiveNotifications(0), mNeedCleanup(false) {}

	inline void Add(Listener* listener)
	{
		boost::mutex::scoped_lock listenerLock(mListenerMutex);
		typename std::vector<Listener*>::iterator it = std::find(mListeners.begin(), mListeners.end(), listener);
		if (it != mListeners.end()) return;
		mListeners.push_back(listener);
	}

	inline void Remove(Listener* listener)
	{
		boost::mutex::scoped_lock listenerLock(mListenerMutex);
		typename std::vector<Listener*>::iterator it = std::find(mListeners.begin(), mListeners.end(), listener);
		if (it == mListeners.end()) return;
		if (mNumActiveNotifications > 0)
		{
			*it = NULL;
			mNeedCleanup = true;
		}
		else
		{
			mListeners.erase(it);
		}
	}

	inline void Notify(const boost::function<void (Listener*)> callback)
	{
		boost::mutex::scoped_lock listenerLock(mListenerMutex);
		++mNumActiveNotifications;
		const size_t numListeners = mListeners.size();
		for (size_t i = 0; i < numListeners; ++i)
		{
			Listener* listener = mListeners[i];
			if (listener != NULL)
			{
				listenerLock.unlock();
				callback(listener);
				listenerLock.lock();
			}
		}
		--mNumActiveNotifications;
		if (mNumActiveNotifications == 0 && mNeedCleanup)
		{
			mListeners.erase(std::remove(mListeners.begin(), mListeners.end(), (Listener*)NULL),
							 mListeners.end());
			mNeedCleanup = false;
		}
	}

/*
	inline size_t Size()
	{
		boost::mutex::scoped_lock listenerLock(mListenerMutex);
		return mListeners.size();
	}

	inline Listener* operator[](size_t index)
	{
		boost::mutex::scoped_lock listenerLock(mListenerMutex);
		if (index >= mListeners.size()) return NULL;
		return mListeners[index];
	}
*/
private:
	std::vector<Listener*> mListeners;
	int mNumActiveNotifications;
	bool mNeedCleanup;
	boost::mutex mListenerMutex;
};

#endif /* LISTENERLIST_H_ */

3
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?