Home > database >  Capturing boost::asio::thread_pool in lambda function
Capturing boost::asio::thread_pool in lambda function

Time:06-13

I'm trying to capture thread_pool object in a lambda function. This lambda function is called inside a thread. Upon this call, it creates(obtains) a new thread with asio::post. However, it throws segmentation fault. I tried create weak ptr with shared_ptr<thread_pool> but it didn't work as well. Simple example written below,

void thread1(std::function<void()> createThread) {
  createThread();
  while (true) {
    sleep(1);
  }
}

void thread2() {
  cout << "You made it";
}

int main(int argc, char **argv) {
  boost::asio::thread_pool pool(std::thread::hardware_concurrency());

  std::function<void()> createThread;
  createThread = [&pool] () {
    boost::asio::post(pool, boost::bind(thread2));
    return true;
  };

  boost::asio::post(pool, boost::bind(thread1, createThread));

  pool.join();

}

It works if I create another thread_pool object inside the lambda function. However, this is not the right way to do this. Therefore, I am open for your suggestions.

CodePudding user response:

Is this one what you look for? :

typedef std::unique_ptr<boost::asio::io_service::work> work_ptr;
std::atomic<bool> closeFlag(false);

int main(int argc, char** argv) {
    boost::asio::io_service service;

    // keep the workers occupied
    work_ptr work(new boost::asio::io_service::work(service));
    boost::thread_group workers;
    for(size_t i = 0; i < std::thread::hardware_concurrency();   i) {
        workers.create_thread([&service]() {
            service.run();
        });
    }
    
   service.post([] { std::cout << "You made first job"; });
   service.post([] { std::cout << "You made second job"; });

    while(!closeFlag) {
        boost::this_thread::sleep(boost::posix_time::milliseconds(100));
    }

    service.stop();
    work.reset(); // destroy work object: signals end of work
    workers.join_all(); // wait for all worker threads to finish
    return 0;
}

CodePudding user response:

I'd simplify:

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

void thread1(std::function<void()> createThread) {
    createThread();
    while (true) {
        std::cout << "Sleeping" << std::endl;
        sleep(1);
    }
}

void thread2() { std::cout << "You made it" << std::endl; }

int main() {
    boost::asio::thread_pool pool;

    post(pool,
         boost::bind(thread1, [&pool]() { post(pool, boost::bind(thread2)); }));

    pool.join();
}

Note the endl that forces stdout to flush, which helps getting results you can expect.

HOWEVER

There's a code smell with:

  • using explicit "threads" when using a thread-pool
  • nullary bind expressions
  • createThread doesn't (create a thread)
  • passing references to execution contexts. Instead, pass executors

Applying these:

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

using Executor = boost::asio::thread_pool::executor_type;

void task_loop(Executor ex, std::function<void()> task) {
    while (true) {
        post(ex, task);
        sleep(1);
    }
}

void task_function() { std::cout << "Task executes" << std::endl; }

int main() {
    boost::asio::thread_pool pool;

    post(pool, boost::bind(task_loop, pool.get_executor(), task_function));

    pool.join();
}

Prints each second:

Task executes
Task executes
...
  • Related