Search code examples
c++c++11boostboost-asioboost-bind

boost:bind and io_service in two different classes


I am kind'a new to Boost.

I would like to know how to construct an io_service in one class and send it tasks from another class.

My problem is BOOST_ASIO_COMPLETION_HANDLER_CHECK complains and wont let the code compile.

He is a skeleton of my code:

type_defs.h (this has the function to be wrapped and sent to the io_service)

#include "boost/filesystem.hpp"

namespace fs = ::boost::filesystem;

typedef boost::function<void(const fs::path path)> parse_and_aggregate_fun_t;

io_service_processors.h (this is the class that will construct the io_service and wait for job posts).

namespace asio = boost::asio;

typedef std::unique_ptr<asio::io_service::work> work_ptr;

class io_service_processors {
public:
    io_service_processors(int tc);
    virtual ~io_service_processors();

    void init();
    void post_job(parse_and_aggregate_fun_t file_job);

private:
    int thread_count;
    asio::io_service* service;
    boost::mutex mtx;
    work_ptr * work;
    boost::thread_group workers;
};

io_service_processors.cpp

namespace asio = boost::asio;   

io_service_processors::io_service_processors(int tc):thread_count(tc) {

}

io_service_processors::~io_service_processors() {
       // clean up code here removed.
}

void io_service_processors::init() {
    this->service = new asio::io_service();
    this->work = new work_ptr(new asio::io_service::work(*(this->service)));
    for(int i = 0; i < this->thread_count; ++i)
        this->workers.create_thread(boost::bind(&asio::io_service::run, this->service));
}

void io_service_processors::post_job(parse_and_aggregate_fun_t file_job) {
    this->service->post(file_job);
}

job_discoverer.cpp (this one will discover files and send their paths to to the io_service, the function parse_and_aggregate will the actual work for opening the file and processing it, process will simply post the wrapped function to the io_service, this->processor is simply a pointer to the io_service wrapper class above).

void job_discoverer::process(const fs::path path){
    std::cout << "Posting file: " << path.string() << std::endl;
    if(this->processor)
        this->processor->post_job(
                boost::bind(&job_discoverer::parse_and_aggregate, this, path)
                );
}

void job_discoverer::parse_and_aggregate(const fs::path path) {
    std::cout << "Parsing and aggregating file: " << path.string() << std::endl;
}

Solution

  • this->service->post(file_job);
    

    tries to post a job, but it's not a nullary function. Of course this can't work. Did you mean to bind a value to the path parameter?

    Even more interesting, that function (io_service_processors::post_job) is never used. If we - for humor sake - assume that post_job was actually meant where post_file_job was written, then you'll find that you actually pass a nullary bind-expression. So, fix it:

    typedef boost::function<void()> any_job;
    

    Live On Coliru

    #include <boost/filesystem.hpp>
    #include <boost/bind.hpp>
    #include <boost/thread.hpp>
    #include <boost/function.hpp>
    
    namespace fs = ::boost::filesystem;
    
    typedef boost::function<void()> any_job;
    
    #include <boost/asio.hpp>
    namespace asio = boost::asio;
    
    typedef std::unique_ptr<asio::io_service::work> work_ptr;
    
    class io_service_processors {
    public:
        io_service_processors(int tc);
        virtual ~io_service_processors();
    
        void init();
        void post_job(any_job file_job);
    
    private:
        int thread_count;
        asio::io_service* service;
        boost::mutex mtx;
        work_ptr * work;
        boost::thread_group workers;
    };
    
    io_service_processors::io_service_processors(int tc):thread_count(tc) {
    
    }
    
    io_service_processors::~io_service_processors() {
           // clean up code here removed.
    }
    
    void io_service_processors::init() {
        this->service = new asio::io_service();
        this->work = new work_ptr(new asio::io_service::work(*(this->service)));
        for(int i = 0; i < this->thread_count; ++i)
            this->workers.create_thread(boost::bind(&asio::io_service::run, this->service));
    }
    
    void io_service_processors::post_job(any_job file_job) {
        std::cout << __PRETTY_FUNCTION__ << "\n";
        this->service->post(file_job);
    }
    
    struct job_discoverer {
    
        boost::optional<io_service_processors> processor;
    
        void process(const fs::path path){
            std::cout << "Posting file: " << path.string() << std::endl;
            if(this->processor)
                this->processor->post_job(
                        boost::bind(&job_discoverer::parse_and_aggregate, this, path)
                        );
        }
    
        void parse_and_aggregate(const fs::path path) {
            std::cout << "Parsing and aggregating file: " << path.string() << std::endl;
        }
    };
    
    int main() {
    }