LINUX.ORG.RU

История изменений

Исправление Manhunt, (текущая версия) :

Управление временем жизни таски осталось полностью за скобками. Код не тестировал, это просто иллюстрация идеи.

#include <boost/intrusive/slist.hpp>
#include <boost/utility.hpp>

#include <condition_variable>
#include <mutex>
#include <cassert>

using namespace boost::intrusive;

class Queue;

class TaskBase : public slist_base_hook<link_mode<normal_link> >, boost::noncopyable
{
	friend class Queue;
	typedef slist<TaskBase, linear<true>, cache_last<true> > List;

	bool m_isInQueue;
public:

	TaskBase() : m_isInQueue(false) {}
	virtual ~TaskBase()  { assert(!m_isInQueue); }

	virtual void Execute() = 0;
};

class Queue
{
	TaskBase::List m_list;
	std::mutex m_mutex;
	std::condition_variable m_condition;
public:
	void Push(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		assert(!task.m_isInQueue);

		m_list.push_back(task);
		task.m_isInQueue = true;

		m_condition.notify_one();
	}
	bool Cancel(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		if(!task.m_isInQueue)
			return false;

		TaskBase::List::iterator it = m_list.iterator_to(task);
		m_list.erase(it);
		task.m_isInQueue = false;

		return true;
	}
	TaskBase &Pop()
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		while(m_list.empty())
			m_condition.wait(lock);

		TaskBase &task = m_list.front();
		m_list.pop_front();
		task.m_isInQueue = false;
		return task;
	}
};

Исправление Manhunt, :

Управление временем жизни таски осталось полностью за скобками. Код не тестировал, это просто иллюстрация идеи.

#include <boost/intrusive/slist.hpp>
#include <boost/utility.hpp>

#include <condition_variable>
#include <mutex>
#include <cassert>

using namespace boost::intrusive;

class Queue;

class TaskBase : public slist_base_hook<link_mode<normal_link> >, boost::noncopyable
{
	friend class Queue;
	typedef slist<TaskBase, linear<true>, cache_last<true> > List;

	bool m_isInQueue;
public:

	TaskBase() : m_isInQueue(false) {}
	~TaskBase()  { assert(!m_isInQueue); }

	virtual void Execute() = 0;
};

class Queue
{
	TaskBase::List m_list;
	std::mutex m_mutex;
	std::condition_variable m_condition;
public:
	void Push(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		assert(!task.m_isInQueue);

		m_list.push_back(task);
		task.m_isInQueue = true;

		m_condition.notify_one();
	}
	bool Cancel(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		if(!task.m_isInQueue)
			return false;

		TaskBase::List::iterator it = m_list.iterator_to(task);
		m_list.erase(it);
		task.m_isInQueue = false;

		return true;
	}
	TaskBase &Pop()
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		while(m_list.empty())
			m_condition.wait(lock);

		TaskBase &task = m_list.front();
		m_list.pop_front();
		task.m_isInQueue = false;
		return task;
	}
};

Исходная версия Manhunt, :

Управление временем жизни таски осталось полностью за скобками. Код не тестировал, это просто иллюстрация идеи.

#include <boost/intrusive/slist.hpp>
#include <boost/utility.hpp>

#include <condition_variable>
#include <mutex>
#include <cassert>

class Queue;

class TaskBase : public boost::intrusive::slist_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link> >, boost::noncopyable
{
	friend class Queue;
	typedef boost::intrusive::slist<TaskBase, boost::intrusive::linear<true>, boost::intrusive::cache_last<true> > List;

	bool m_isInQueue;
public:

	TaskBase() : m_isInQueue(false) {}
	~TaskBase()  { assert(!m_isInQueue); }

	virtual void Execute() = 0;
};

class Queue
{
	TaskBase::List m_list;
	std::mutex m_mutex;
	std::condition_variable m_condition;
public:
	void Push(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		assert(!task.m_isInQueue);

		m_list.push_back(task);
		task.m_isInQueue = true;

		m_condition.notify_one();
	}
	bool Cancel(TaskBase &task)
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		if(!task.m_isInQueue)
			return false;

		TaskBase::List::iterator it = m_list.iterator_to(task);
		m_list.erase(it);
		task.m_isInQueue = false;

		return true;
	}
	TaskBase &Pop()
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		while(m_list.empty())
			m_condition.wait(lock);

		TaskBase &task = m_list.front();
		m_list.pop_front();
		task.m_isInQueue = false;
		return task;
	}
};