自动删除发送到异步函数/ io_service的容器

时间:2015-09-01 15:11:56

标签: c++ pointers boost shared-ptr boost-bind

我想使用unordered_map作为作业或会话上下文对象。所以,我想在函数对象中分配一个函数对象中的静态函数,并将此函数对象发送到io_service。显然,我不担心解除分配。

关于如何做到这一点的任何想法?

谢谢!

#include <iostream>
#include <unordered_map>
#include "boost/asio.hpp"
#include "boost/thread.hpp"

using namespace std;
namespace asio = boost::asio;

typedef std::unique_ptr<asio::io_service::work> work_ptr;
typedef boost::function<void(void) > boost_void_void_fun;

class job_processor {
public:

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

    void post_task(boost_void_void_fun job) {
        this->service->post(job);
    }

    void drain() {
        this->work->reset();
    }

    void wait() {
        this->workers.join_all();
    }
private:
    int thread_count;
    work_ptr * work;
    asio::io_service* service;
    boost::thread_group workers;
};

typedef std::unordered_map<string, unsigned long> map_t;

class with_static_function {
public:

    static void print_map(map_t map) {
        for(map_t::iterator it = map.begin(); it != map.end(); ++it)
            std::cout << it->first << ":" << it->second << std::endl;
    }

    static void print__heap_map(map_t* map) {
        if(!map) return;
        for(map_t::iterator it = map->begin(); it != map->end(); ++it)
            std::cout << it->first << ":" << it->second << std::endl;
    }    
};

int main(int argc, char** argv) {
    map_t words;
    words["one"] = 1;

    // pass the reference;
    with_static_function::print_map(words);
    job_processor *pr = new job_processor(4);
    {
        map_t* heap_map = new map_t;
        (*heap_map)["two"] = 2;
        // I need this variable to the job_processor;
        // and I do not want to worry about deallocation.
        // should happen automatically somehow.
        // I am ok with changing the variable to be a shared_ptr or
        // anything else that works.    
        boost_void_void_fun fun = boost::bind(
                &with_static_function::print__heap_map,
                heap_map);
        fun(); // if binding was done right this should have worked.
        pr->post_task(fun);
    }

    pr->drain();
    pr->wait();

    delete pr;

    return 0;
}

1 个答案:

答案 0 :(得分:0)

A number of observations:

  1. Stop Emulating Java. Do not use new unless you're implementing an ownership primitive (smart handle/pointer type). Specifically, just create a pr:

    job_processor pr(4);
    

    Same goes for all the members of job_processor (you were leaking everything, and if job_processor were copied, you'd get double-free Undefined Behaviour

  2. The code

    // pass the reference;
    with_static_function::print_map(words);
    

    passes by value... meaning the whole map is copied

  3. to avoid that copy, fix the print_map signature:

    static void print_map(map_t const& map) {
        for(map_t::const_iterator it = map.begin(); it != map.end(); ++it)
            std::cout << it->first << ":" << it->second << std::endl;
    }
    

    Of course, consider just writing

    static void print_map(map_t const& map) {
        for(auto& e : map)
            std::cout << e.first << ":" << e.second << "\n";
    }
    
  4. The "heap" overload of that could be, as my wording implies, an overload. Be sure to remove the useless duplication of code (!):

    static void print_map(map_t const* map) {
        if (map) print_map(*map);
    }
    
  5. You don't even need that overload because you can simply use a lambda to bind (instead of boost::bind):

    auto heap_map = boost::make_shared<map_t>();
    heap_map->insert({{"two", 2}, {"three", 3}});
    
    boost_void_void_fun fun = [heap_map] { with_static_function::print_map(*heap_map); };
    

Complete working program:

Live On Coliru

#include <iostream>
#include <unordered_map>
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

namespace asio = boost::asio;

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

class job_processor {
public:

    job_processor(int threads) : service(), work(boost::asio::io_service::work(service))
    {
        for (int i = 0; i < threads; ++i)
            workers.create_thread(boost::bind(&asio::io_service::run, &service));
    }

    void post_task(boost_void_void_fun job) {
        service.post(job);
    }

    void drain() {
        work.reset();
    }

    void wait() {
        workers.join_all();
    }
private:
    asio::io_service service;
    boost::optional<asio::io_service::work> work;
    boost::thread_group workers;
};

typedef std::unordered_map<std::string, unsigned long> map_t;

namespace with_static_function {
    static void print_map(map_t const& map) {
        for(auto& e : map)
            std::cout << e.first << ":" << e.second << "\n";
    }
}

int main() {
    // pass the reference;
    with_static_function::print_map({ { "one", 1 } });

    job_processor pr(4);
    {
        auto heap_map = boost::make_shared<map_t>();
        heap_map->insert({{"two", 2}, {"three", 3}});

        boost_void_void_fun fun = [heap_map] { with_static_function::print_map(*heap_map); };
        pr.post_task(fun);
    }

    pr.drain();
    pr.wait();
}

Prints

one:1
three:3
two:2