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

boost::bind member function as argument inside its own member function


I am following a tutorial (https://www.gamedev.net/blogs/entry/2249317-a-guide-to-getting-started-with-boostasio/) for boost asio.

Now I want to convert some of the aspects of this tutorial to a class, to learn more about what actually goes on within each part of the code. So I am trying to boost bind this:

class LDserver
{
public:
    void workerThread(boost::shared_ptr<boost::asio::io_service> io_service)   
        {
            io_service->run();    
        } 
    void createThreads()
        {
            this->worker_threads.create_thread(boost::bind(&LDserver::workerThread, this->io_service));
        }
    
        ~LDserver() = default;
        boost::thread_group worker_threads;
        boost::shared_ptr<boost::asio::io_service> io_service = boost::make_shared<boost::asio::io_service>();
        boost::shared_ptr<boost::asio::io_service::work> work = boost::make_shared<boost::asio::io_service::work>(*this->io_service);
        boost::asio::io_service::strand strand = boost::asio::io_service::strand(*this->io_service);
};

Following the documentation, it states that this should be the correct syntax AS its own, so not as an argument. But instead I am greeted with an error message coming from the boost::bind library.

Severity    Code    Description Project File    Line    Suppression State
Error   C2440   'return': cannot convert from 'R (__cdecl &)' to 'R'    LockManager C:\Boost\boost_1_75_0\boost_1_75_0\boost\bind\bind.hpp  227 

It work fine if I follow the documentation and put it in the mainloop, it even takes the member variable fine as an argument:

LDserver s1;
for (int i = 0; i <= 2; i++)
    {
        s1.worker_threads.create_thread(boost::bind(&workerThread, s1.io_service));
    }

And by commenting out I am 100% sure because it doesnt take my way of syntaxing the worketThread() member function as the correct one, however after spending 2 days of trying and finding the answer, I hope someone here could enlighten me.


Solution

  • The problem is that the thread function isn't static, so it needs an argument for this (LDServer*). Or you can make it static:

      static void workerThread(boost::shared_ptr<ba::io_service> io_service) {
          io_service->run();
      }
      void createThreads() {
          worker_threads.create_thread(
              boost::bind(&LDserver::workerThread, io_service));
      }
    

    However, all the rampant dynamic allocation, shared ownership and manual threading, as well as the boost bind/shared_ptr instead of standard library are all code smells. If you're using a VeryOldOrBadBook(TM) to learn this from, please compare:

    #include <boost/asio.hpp>
    namespace net = boost::asio;
    
    class LDserver : public std::enable_shared_from_this<LDserver> {
        using executor_type = net::thread_pool::executor_type;
    
        net::thread_pool           _ctx{1}; // one thread please
        net::strand<executor_type> _strand{_ctx.get_executor()};
    
      public:
        ~LDserver() {
            _ctx.join(); // don't forget to join your threads anyway
        }
    };