Sign in to follow this  
Wizumwalt

help create events w/ boost

Recommended Posts

I'm new to boost and what I'm doing seems very simple, but I can't get it. I want to store 3 events onto a priority_queue and have them execute n seconds from the time they were created, n is a randomly generated amount of time between 0 and 10 seconds.
// create container that holds function objects
priority_queue<boost::function<void (Event)> > pq;

// create 3 events and place in priority_queue 
boost::bind(destroy_target, placeholders::_1, 'pq');
boost::bind(destroy_target, placeholders::_1, 'pq');
boost::bind(destroy_target, placeholders::_1, 'pq');
I think I now have 3 function objects on the queue, but I don't know how to pull the Event object off the queue and check f it's timestamp is expired, and if so execute the function object that was stored on the queue.
// get the first event off the priority_queue, and if expired, execute destroy_target().
Event e = pq.top()(Event());

// this is the function I eventually want my event to execute
void destroy_target() { ... }
Any help is greatly appreciated.

Share this post


Link to post
Share on other sites
Look more closely at your documentation for priority_queue. They know nothing of time.

Elements of a priority_queue are sorted according to std::less<>, which by default uses the < operator.

So, you should create a wrapper around function<void (Event)> that also holds the time of construction and then define an operator< that compares these time stamps.

Share this post


Link to post
Share on other sites
Also, you're using boost function and boost bind incorrectly. The signature boost::function<void (Event)> means a function which returns void, and takes a single argument of type event.

When you bind your functions, you bind 'pq' to the first parameter for the function destroy_target. This won't work since:
1) 'pq' doesn't make sense, single quotes are for characters (eg. 'a'), double quotes are for strings (eg. "abc")
2) You don't do anything with the returned bound function
3) destroy_target doesn't actually take any arguments, so you can't bind anything to it!

Also, You try to get the first element of the priority_queue and execute the returned boost::function, passing to it a default constructed Event(). But you try to assign the return value of this function to a new Event e, even though the function returns void!

Your comment says that it's supposed to execute destroy_target(), but that's impossible since destroy_target doesn't take any arguments whereas the boost::function in the priority_queue says that the function takes an Event as an argument.

In short, the code doesn't really make sense (or is very horribly broken). I suspect you've tried to type out your code from memory and messed it up - don't do this. Copy and paste the exact code you're trying to compile. We can help, but we need more information first.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
In short, the code doesn't really make sense (or is very horribly broken). I suspect you've tried to type out your code from memory and messed it up - don't do this. Copy and paste the exact code you're trying to compile. We can help, but we need more information first.


Yeah, it was horribly broken and didn't make sense. I'm having a hard time understanding, but I've gotten a bit further and think this is more correct, but a few questions ...


// Is storing a function object onto a queue like below allowable? I'm getting
// errors I can't even begin to understand (posted at bottom).
class Scheduler
{
private:
typedef boost::function<void ()> event;
std::priority_queue<event> pq;

public:
void at(time_t when, event const& what);
}

// Here I create 3 function objects (events) and put them on a queue.
void MyApp::initTimer()
{
type_t now = current_time();

for (int i = 0; i < 3; i++) {
event = bind(&MyApp::print, this);

scheduler->at(now + i, event);
}
}

// But here I'm losing the time when this event is to be excuted.
// How do I store the time so that I can check it in my run() and see
// if time has expired so that it can be executed?
void Scheduler::at(time_t when, event const& what)
{
pq.push(what);
}

// This function gets run in every frame of my game. I was hoping to just
// pull off the top() of the queue, see if time expired, and if so execute the
// function bound to the event. But I think my at() is messed up.
scheduler->run();



And the error I get compiling ...

/bin/sh ../../../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -I../../../../dnr/src/libs/events -I../../.. -I../../../../dnr/include -I/usr/local/include/OGRE -g -O2 -MT Scheduler.lo -MD -MP -MF .deps/Scheduler.Tpo -c -o Scheduler.lo ../../../../dnr/src/libs/events/Scheduler.cpp
g++ -DHAVE_CONFIG_H -I. -I../../../../dnr/src/libs/events -I../../.. -I../../../../dnr/include -I/usr/local/include/OGRE -g -O2 -MT Scheduler.lo -MD -MP -MF .deps/Scheduler.Tpo -c ../../../../dnr/src/libs/events/Scheduler.cpp -fPIC -DPIC -o .libs/Scheduler.o
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = boost::function<void ()(), std::allocator<void> >]':
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_heap.h:279: instantiated from 'void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<boost::function<void ()(), std::allocator<void> >*, std::vector<boost::function<void ()(), std::allocator<void> >, std::allocator<boost::function<void ()(), std::allocator<void> > > > >, _Distance = long int, _Tp = boost::function<void ()(), std::allocator<void> >, _Compare = std::less<boost::function<void ()(), std::allocator<void> > >]'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_heap.h:404: instantiated from 'void std::make_heap(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<boost::function<void ()(), std::allocator<void> >*, std::vector<boost::function<void ()(), std::allocator<void> >, std::allocator<boost::function<void ()(), std::allocator<void> > > > >, _Compare = std::less<boost::function<void ()(), std::allocator<void> > >]'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_queue.h:367: instantiated from 'std::priority_queue<_Tp, _Sequence, _Compare>::priority_queue(const _Compare&, const _Sequence&) [with _Tp = boost::function<void ()(), std::allocator<void> >, _Sequence = std::vector<boost::function<void ()(), std::allocator<void> >, std::allocator<boost::function<void ()(), std::allocator<void> > > >, _Compare = std::less<boost::function<void ()(), std::allocator<void> > >]'
../../../../dnr/src/libs/events/Scheduler.cpp:11: instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_function.h:227: error: no match for 'operator<' in '__x < __y'
make[4]: *** [Scheduler.lo] Error 1

Share this post


Link to post
Share on other sites
The error is saying that there's no less than operator (operator <) for boost::function. This is correct, as it doesn't really make sense for a function to be "less than" another.

the_edd is right here:
Quote:
Original post by the_edd
Elements of a priority_queue are sorted according to std::less<>, which by default uses the < operator.


In other words, you can't have a priority_queue of boost::function's unless you provide a less than comparison operator. In your case, I'm guessing you don't really want a priority_queue here. priority_queue is sorted in that the top of the queue is the one with the largest value. I think you're looking more for std::stack or a regular std::queue, depending on if you want FIFO or LIFO behaviour.

As for storing the time, you can have a struct which stores a time and a function. Like so:

class Scheduler
{
private:
struct Event
{
time_t when;
boost::function<void ()> what;
};
std::stack<Event> events;

public:
void at(time_t when, const Event& what);
void run();
}

void MyApp::initTimer()
{
type_t now = current_time();

for (int i = 0; i < 3; i++)
{
scheduler->at(now + i, bind(&MyApp::print, this));
}
}

void Scheduler::at(time_t when, const Event& what)
{
Event e;
e.when = when;
e.what = what;
events.push(e);
}

void Scheduler::run()
{
if(events.empty())
return;
Event e = events.top();
if(e.when == current_time()) // If it's time to run the event
{
e.what(); // Execute the event function
events.pop(); // Remove the event we just executed
}
}



The code is untested, but you get the idea.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
In your case, I'm guessing you don't really want a priority_queue here. priority_queue is sorted in that the top of the queue is the one with the largest value. I think you're looking more for std::stack or a regular std::queue, depending on if you want FIFO or LIFO behaviour.


Thanks, this is very helpful, but I'm thinking I need a priority_queue and prioritize from the event w/ the least amount of time, and once the current_time is > than the item on the priority_queue w/ the least amount of seconds, then it gets executed (time's expired, exec event). I will always be looking for the event w/ the lowest amount of time in the queue because only that one can be executed next. Is my thinking correct there?

Share this post


Link to post
Share on other sites
Quote:
Original post by Wizumwalt
Quote:
Original post by Sc4Freak
In your case, I'm guessing you don't really want a priority_queue here. priority_queue is sorted in that the top of the queue is the one with the largest value. I think you're looking more for std::stack or a regular std::queue, depending on if you want FIFO or LIFO behaviour.


Thanks, this is very helpful, but I'm thinking I need a priority_queue and prioritize from the event w/ the least amount of time, and once the current_time is > than the item on the priority_queue w/ the least amount of seconds, then it gets executed (time's expired, exec event). I will always be looking for the event w/ the lowest amount of time in the queue because only that one can be executed next. Is my thinking correct there?

OK, if that's what you want to do then all you have to do is provide a less than comparison operator in the Event structure:


class Scheduler
{
private:
struct Event
{
time_t when;
boost::function<void ()> what;

bool operator< (const Event& rhs) const
{
return (when < rhs.when);
}
};
std::priority_queue<Event> events;

public:
void at(time_t when, const Event& what);
void run();
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this