简体   繁体   中英

C++ threading with boost asio

I have a thread pool using boosts library's and I have set up in the example below running two threads that get re-run 4 times. What is the best way that I can check is_service to see if all child threads execution are finished, before I can move on in the code? the rest of the code depends on all the child threads finishing before the program can move on. I can get the desired behavior if I put a Sleep(1000) call but this is undesirable, I have looked at a check on io_service_.stopped() but always returns a 0 . Any thoughts would be greatly appreciated.

#include <iostream>                   
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <vector>               
#include <string>

using namespace std;

class Model {
  public:
    // Constructor
    Model() {
        work_ctrl_ = new boost::asio::io_service::work(io_service_);

        for (int i = 0; i < 2; ++i) {
            threads_.create_thread(
                    boost::bind(&boost::asio::io_service::run, &io_service_));
        }
    }
    // Deconstructor
    ~Model() {
        delete work_ctrl_;
    }

    // Function I want to thread
    void manipulate_vector(unsigned start, unsigned last) {
        cout << "entering manipulate vector(), from thread " << boost::this_thread::get_id() << endl;
        for(unsigned k = start; k <= last; ++k)
            my_vector_[k] *= sqrt(32);
        cout << "exit manipulate vector()" << endl;
        Sleep(500); // Add a sleep to mimic a long algorithm being executed
    }

    void update() {
        // Do otherstuff that can't be threaded
        cout << "entering update" << endl;

        // run manipulate_vector() across multiple threads
        // - start thread
        // - execute function call.
        // - stop thread
        io_service_.post(boost::bind(manipulate_vector, this, 0, mid_point_));
        io_service_.post(boost::bind(manipulate_vector, this, mid_point_, my_vector_.size()));

        cout << io_service_.stopped() << endl;

        // keep doing otherstuff that can't be threaded
        cout << "hopefully the threads are finished and I can take that information and continue." << endl;
    }

    void run(void) {
        // call update 10 times
        for(unsigned i = 0; i < 4; ++i) {
            update();
            //Sleep(2000);
        }
    }

    void initialise() {
        // initialise vector
        for(unsigned j = 0; j < 100000000; ++j)
            my_vector_.push_back(j);
        mid_point_ = 49999999;
    }

  private:
    boost::asio::io_service io_service_;
    boost::thread_group threads_;
    boost::asio::io_service::work *work_ctrl_;
    unsigned n_threads_;
    vector<double>  my_vector_;
    unsigned mid_point_;
};

int main() {
    std::cout << "----------Enter Main----------" << std::endl;
    Model model;
    model.initialise();
    model.run();
    std::cout << "----------Exit Main----------" << std::endl;
    system("PAUSE");
}

Presumably you want to know when your work is complete rather than when the threads stop executing (they won't until you call io_service.stop() or delete work-ctrl_ ).

The standard solution is to use a condition variable:

std::mutex mutex;
std::condition_variable condition;
int workCount;

void manipulate_vector(unsigned start, unsigned last) {
    cout << "entering manipulate vector(), from thread " << boost::this_thread::get_id() << endl;
    for(unsigned k = start; k <= last; ++k)
        my_vector_[k] *= sqrt(32);
    cout << "exit manipulate vector()" << endl;
    Sleep(500); // Add a sleep to mimic a long algorithm being executed
    std::unique_lock<std::mutex> lock(mutex);
    workCount--;
    condition.notify_one();
}

void update() {
    // Do otherstuff that can't be threaded
    cout << "entering update" << endl;

    // run manipulate_vector() across multiple threads
    // - start thread
    // - execute function call.
    // - stop thread
    workCount = 2;
    io_service_.post(boost::bind(manipulate_vector, this, 0, mid_point_));
    io_service_.post(boost::bind(manipulate_vector, this, mid_point_, my_vector_.size()));
    {
       std::unique_lock<std::mutex> lock(mutex);
       condition.wait(lock, [&]{ return workCount == 0; });
    }
}

If you are OK with some of the work being run in the current thread, you can call io_service_.run() where you want to wait after deleting work_ctrl_ . When it returns there is no work left and you can safely proceed. You could reduce your level of concurrency in the thread group by one to get the same overall concurrency.

A simple alternative is simply to call threads_.join_all() after all the posts have been queued and you have deleted work_ctrl_ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM