У меня есть следующие два заголовка.
#ifndef DRD_EVENT_HPP
#define DRD_EVENT_HPP
#include <functional>
namespace drd
{
template <typename Clock>
class event
{
public:
using clock = Clock;
using time_point = typename clock::time_point;
template <class F, class... Args>
event(time_point et, F&& f, Args&&... args) :
Task(std::bind<void>(std::forward<F>(f), std::forward<Args>(args)...)),
Time(et) {}
void perform() ///Can throw std::bad_function_call
{
Task();
Task = nullptr;
}
///Returns the event time.
time_point time() const noexcept
{ return Time; }
///Checks if the event has not been performed yet.
bool pending() const noexcept
{ return static_cast<bool>(Task); }
private:
std::function< void()> Task;
time_point Time;
};
struct later_event
{
template <class Clock>
bool operator()(const event<Clock>& lhs, const event<Clock>& rhs)
const noexcept
{
return lhs.time() > rhs.time();
}
};
}
#endif // DRD_EVENT_HPP#ifndef DRD_DISCRETE_SIMULATION_HPP
#define DRD_DISCRETE_SIMULATION_HPP
#include <exception>
#include <chrono>
#include <queue>
#include "event.hpp"
namespace drd
{
namespace des ///Discrete event simulation
{
template <class Rep, class Period = std::ratio<1>>
class simulation_engine
{
public:
class clock;
using time_point = typename clock::time_point;
using duration = typename clock::duration;
using event_type = event<clock>;
public:///Constructs an event "in-place" and inserts it in the events list
template <typename... EventArgs>
void schedule(EventArgs&&... event_args_)
{
EventsList.emplace(std::forward<EventArgs>(event_args_)...);
}
bool has_pending_events() const noexcept
{ return not EventsList.empty(); }///Advances the clock until the next event time and then the event
///is performed, if the events list was empty the behavior is undefined.
void next_event()
{
auto Event = EventsList.top();
EventsList.pop();
clock::advance_until(Event.time());
Event.perform();
}
///Calls next_event() while the events list is not empty.
void simulate()
{ while (has_pending_events()) next_event();}///Performs all of events whose time is scheduled before or just at the
///moment t, then advances the clock until t.
void simulate_until(time_point t)
{
while(has_pending_events() and EventsList.top().time() <= t)
next_event();
clock::advance_until(t);
}
void simulate_for(duration d)
{ simulate_until(clock::now() + d); }private:
std::priority_queue<event_type, std::vector<event_type>,
later_event> EventsList;
};///clock type that is thread-independent and adjustable by
///simulation_engine
template <class Rep, class Period>
class simulation_engine<Rep,Period>::clock
{
public:
using rep = Rep;
using period = Period;
using duration = std::chrono::duration<rep,period>;
using time_point = std::chrono::time_point<clock>;
public:
static constexpr bool is_steady = false;
public:
static time_point now() noexcept
{ return CurrentTime;}
private:
static void reset() noexcept
{ CurrentTime = time_point(); }
static void adjust(time_point t) noexcept
{ CurrentTime = t; }
static void advance_until(time_point t)
{
if(t < CurrentTime)
throw std::logic_error("advance_until cannot set the clock back.");
CurrentTime = t;
}
friend simulation_engine<Rep,Period>;
private:
static thread_local time_point CurrentTime;
};
template <class Rep, class Period>
thread_local typename simulation_engine<Rep,Period>::clock::time_point
simulation_engine<Rep,Period>::clock::CurrentTime;}
}
#endif //DRD_DISCRETE_SIMULATION_HPP
Мне было интересно, должен ли я сделать функции-члены Simulation_engine статическими, потому что объекты владеют независимым списком событий и используют одни и те же часы и могут возникнуть проблемы с синхронизацией.
Что я должен делать?
Извините за мой английский и обширный код.
Я надеюсь, что ваш ответ, заранее спасибо.
Я наконец решил сделать это, я думаю, что это гораздо безопаснее и полезнее
struct bad_event_scheduling : std::logic_error
{
bad_event_scheduling() :
std::logic_error("bad_event_scheduling") {}
};
template <class Clock>
class simulator
{
public:
using clock = Clock;
using time_point = typename clock::time_point;
using duration = typename clock::duration;
using event_type = event<clock>;
private:
using calendar_type = std::priority_queue<event_type,
std::vector<event_type>, later_event>;
public:
void reset()
{
CurrentTime = time_point();
EventsList = calendar_type();
}
time_point current_time() const noexcept
{
return CurrentTime;
}
///Constructs an event "in-place" and inserts it in the events list
template <typename... OtherArgs>
void schedule(const time_point& et, OtherArgs&&... other_args_)
{
if(et < CurrentTime) throw bad_event_scheduling();
EventsList.emplace(et, std::forward<OtherArgs>(other_args_)...);
}
bool has_pending_events() const noexcept
{ return not EventsList.empty(); }///Advances the clock until the next event time and then the event
///is performed, if the events list was empty the behavior is undefined.
void next_event()
{
auto Event = EventsList.top();
EventsList.pop();
CurrentTime = Event.time();
Event.perform();
}
///Calls next_event() while the events list is not empty.
void simulate()
{ while (has_pending_events()) next_event();}///if t >= current_time(), performs all of events whose time is scheduled
///before or just at the moment t, and then advances the current time until t.
void simulate_until(const time_point& t)
{
if( t >= CurrentTime)
{
while(has_pending_events() and EventsList.top().time() <= t)
next_event();
CurrentTime = t;
}
}
void simulate_for(const duration& d)
{ simulate_until(CurrentTime + d); }
private:
calendar_type EventsList;
time_point CurrentTime;
};
Если вы все переменные собираетесь быть статическими, то имеет смысл иметь статические функции-члены. Однако если нет, то у вас не должно быть всех статических функций. Если вы хотите, чтобы он был потокобезопасным, вам следует также заблокировать все функции. Я думаю, что вы также можете реализовать шаблон проектирования Singleton.http://en.wikipedia.org/wiki/Singleton_pattern