Search code examples
c++multithreadingboostasio

Creating thread bound to io_service inside a struct


I'm trying to create a simple struct that contains a boost::thread object. This struct (ApplicationPair)'s constructor requires an io_service reference object to be passed and a method; for now, I'm using a void method with no parameters, for simplicity. After that, the thread is created with boost::bind.

ApplicationPair.h

#ifndef APPLICATIONPAIR_H
#define APPLICATIONPAIR_H

#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <cstdarg>

template<typename T>
struct ApplicationPair
{
    ApplicationPair(boost::asio::io_service& iSvc, boost::function<T()> func ) : _func(func)
    {
        iSvc.post(boost::bind(&ApplicationPair<T>::run, this));
        thr = boost::thread(boost::bind(&boost::asio::io_service::run, &iSvc));
    }
    ApplicationPair() = delete;
    ~ApplicationPair() { if (thr.joinable()) thr.join(); }

    void run(); 
    boost::thread thr;
    boost::function<T()> _func;
};

#endif

The idea here is that every new ApplicationPair object I create will have its own thread on the io_service, and will launch any method I want upon instantiation.

Here's the main:

main.cpp

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <cstdio>

boost::asio::io_service iSvc;

void HelloWorld()
{
    std::cout << "HelloWorld\n";
}

template<typename T>
void ApplicationPair<T>::run()
{
    this->_func();
}
int main()
{
    ApplicationPair<void> p1(boost::ref(iSvc), HelloWorld);
    ApplicationPair<void> p2(boost::ref(iSvc), HelloWorld);
    ApplicationPair<void> p3(boost::ref(iSvc), HelloWorld);
    return 0;
} 

And here's where I realize things are going terribly: my expected output would be 3 "HelloWorld" prints, however I only get 2. What's even stranger is that if I run the debug, and proceed further instruction by instruction, HelloWorld is printed only once!

I'm honestly clueless, but it's clear to me that I'm not fully understanding how multithreading and io_services work, and the documentation on Boost.org doesn't help AT ALL.


Solution

  • As you suspected you are missing some key points about ASIO.

    You state you desire for each ApplicationPair to have its own thread on the io_service. This is not really how it works. Once you call io_service.run() on a thread that thread is now owned by the io_service. The io_service will schedule events as it sees fit.

    Think of it more like a thread pool, you post task to the io_service and it schedules them to the pool.

    Also, you should look at strands. This is like the ASIO version of a mutex. It functions similarly, but is conceptually different.boost::asio strand example

    This may not seem important here because you are not reading to or writing from variables, however std::cout is a global resource which you must manage.

    I tried to rework your code to give you an example, but these differences are going to change it dramatically. And I am not exactly sure what your end goal is so its hard to provide an example.

    Also these are some good youtube videos: asio::strand asio basics