Dainius Kreivys
Dainius Kreivys

Reputation: 535

From boost::threads to boost::asio timers

In my project every class object has its own thread with infinite cycle (while(1)) inside, in which particular object functions are performed. And I'm trying to change this so that every object would perform its functions asynchronously with timers.

Basically this is how it works with thread with infinite loop:

class obj
{
    public:
          obj();
          ~obj();
         //custom functions and variables
        int x;
        int obj_action;
        move();
        wait();

}

obj()
{
     obj_action=1;
     //when constructing object, make its thread with infinite while cycle
     boost::thread make_thread(boost::bind(&obj::obj_engine,this));
}

void obj::obj_engine()
{
     while(true)
     {
       if (obj_action==1){move();}
       else if (obj_action==2){wait();}
       Sleep(1);
     }
}

void obj::move()
{
      x++;
      obj_action==2;
}


void obj::wait()
{
      Sleep(5000);
      obj_action==1;
}

This example shows, the obj class, which has constructor , destructor, couple of variables and couple of functions. When constructing an object (obj()), thread is made. Thread contains a function "obj_engine" , which has infinite loop (while(true)). In the loop there is two functions: 1. wait() - makes a thread sleep for 5 seconds. 2. walk() - simply x+1 those 2 functions switches each other after its end by defining obj_action.

Now I want to change this to, when the constructing and object , asynchronously move() function would be performed, and after move() function, asynchronously wait() function would be performed, and vice verse. So I wouldn't need to use any threads.

I hoping for result like this:

//constructing
obj()
{
       asynchronous(walk());
}

walk()
{
    x++
    asynchronous(wait());
}

wait()
{
    Sleep(5000);
    asynchronous(walk());
}

I heard you can do this, with boost::asio timers , but I really don't know how. I would be very grateful if someone would show me how.

Upvotes: 1

Views: 3969

Answers (2)

Rawler
Rawler

Reputation: 1610

Borrowing the example from nijansen, I've whipped together something that should be more similar to what you want (I think).

The key here is the io_service should be shared between all object's scheduling on it. Usually there is one io_service per thread, but more intricate schemes can be used as well. io_service::run runs for as long as there is work scheduled on the io_service (pending timeout or waiting on a socket). When no more work is scheduled, it simply returns.

You might be interested in io_service::post as a way to send messages between your "active objects" (which works even if they are running under different io_services and different threads). You may want to look at boost::bind and possibly boost::signals.

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
#include <iostream>

namespace asio = boost::asio;

class obj {
public:
    obj(asio::io_service& ioSvc)
      : x_(0), t_(ioSvc)
    {
        schedule_in(5);
    }

    void schedule_in(int seconds) {
        t_.expires_from_now(boost::posix_time::seconds(3));
        t_.async_wait(boost::bind(&obj::move, this));
    }

    void move() {
        x_++;
        std::cout << x_ << std::endl;
        schedule_in(5);
    }

private:
    int x_;
    boost::asio::deadline_timer t_;
};

int main(int, char**) {
    boost::asio::io_service io_service;
    obj a(io_service);
    obj b(io_service);
    obj c(io_service);
    io_service.run();
}

Upvotes: 2

nikolas
nikolas

Reputation: 8975

Here you go:

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
#include <iostream>



class obj {
public:
    obj() : x_(0), t_(io_service_, boost::posix_time::seconds(5)) {
        t_.async_wait(boost::bind(&obj::move, this));
        io_service_.run();
    }

    void move() {
        x_++;
        std::cout << x_ << std::endl;
        t_.expires_at(t_.expires_at() + boost::posix_time::seconds(5));
        t_.async_wait(boost::bind(&obj::move, this));
    }

private:
    int x_;
    boost::asio::io_service io_service_;
    boost::asio::deadline_timer t_;
};

int main(int, char**) {
    obj a;
    while(true);
}

Basically everything you need is covered by the asio tutorial: this tutorial shows you how to use an asynchronous timer, and this tutorial shows you how to reset your timer.

Update:

Please use the above source code instead of my initial one - due to the repetitive calls of io_service_.run(), each move call would be called in another thread and after some time your application would crash because of it. The above code fixes this problem, and gets rid of the wait function by doing so.

Upvotes: 2

Related Questions