История изменений
Исправление 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;
}
};