Bonjour,
Je rencontre quelques problèmes avec une threadpool codée moi-même.
Je n'utilise pas de threadpool déjà existante car j'ai besoin d'un système de Task un peu spécial.
Ma threadpool gère mes classes Executor et ConnectionListener.
Mon executor gère les threads workers et les connectionListener gèrent les connexions au programme (deux types de connexions dont 2 listeners).
Allons-y pour le code :
Thread.hpp
ThreadPool.hpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class Thread { public: Thread () : _thread (NULL) {} virtual ~Thread () {} virtual void run () = 0; void terminate () { if (_thread != NULL) _thread->interrupt(); } void set_thread (boost::thread * t) { _thread = t; } private: boost::thread * _thread; };
ThreadPool.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 class ThreadPoolManager { public: void start_up (); void shutdown (); bool running () const { return is_running; } void schedule (Task * t); void launch (Thread * t, bool delete_t); unsigned garbage_collector (); private: ThreadPoolManager (); ~ThreadPoolManager () { } bool is_running; set< pair<Thread *, bool> > _threads; boost::shared_ptr< boost::asio::io_service > _io_service; boost::shared_ptr< boost::asio::io_service::work > _work; ThreadPoolExecutor _executor; };
Executor.hpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 ThreadPoolManager::ThreadPoolManager () : _io_service (new boost::asio::io_service), _work (new boost::asio::io_service::work (*_io_service)), _executor (_io_service) { launch (&_executor, false); } void ThreadPoolManager::start_up () { if (!is_running) is_running = true; } void ThreadPoolManager::shutdown () { if (!is_running) return; is_running = false; for (set<pair<Thread *, bool> >::iterator it = _threads.begin() ; it != _threads.end() ; ++it) { delete it->first->_thread; if (it->second) // si on doit delete le Thread * delete it->first; } _threads.clear(); } void ThreadPoolManager::schedule (Task * t) { if (!is_running) return; _io_service->post (boost::bind (&Task::execute, t, t->_target, t->_data)); // Là j'ai un problème } void ThreadPoolManager::launch (Thread * t, bool delete_t) { if (!is_running) return; boost::thread * new_t = new boost::thread (boost::bind (&Thread::run, t)); t->set_thread (new_t); _threads.insert (make_pair (t, delete_t)); } unsigned ThreadPoolManager::garbage_collector () { list<set<pair<Thread *, bool> >::iterator> to_erase; boost::posix_time::time_duration td = boost::posix_time::milliseconds(1); for (set<pair<Thread *, bool> >::iterator it = _threads.begin() ; it != _threads.end() ; ++it) { if (it->first->_thread->timed_join (td)) { delete it->first->_thread; if (it->second) delete it->first; to_erase.push_back (it); // si on faisait direct un erase, on aurait le droit à un beau plantage "invalid iterator etc" au prochain tour de boucle } } unsigned count = to_erase.size(); for (list<set<pair<Thread *, bool> >::iterator>::iterator it = to_erase.begin() ; it != to_erase.end() ; ++it) _threads.erase (*it); return count; }
Task.hpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 namespace { void worker_thread (boost::shared_ptr< boost::asio::io_service > io_service) { while (true) { io_service->run(); } } } class ThreadPoolExecutor : public Thread { public: ThreadPoolExecutor (boost::shared_ptr< boost::asio::io_service > io_service) { for (int x = 0 ; x < 2 ; ++x) // Pour le moment, seulement 2 workers _workers.create_thread (boost::bind (&worker_thread, io_service)); } ~ThreadPoolExecutor () { _workers.interrupt_all(); } void run () { while (true) { _workers.join_all(); // Quel est réellement l'impact de cette instruction ? boost::this_thread::sleep(boost::posix_time::milliseconds (50)); } } private: boost::thread_group _workers; };
Pour le moment, deux problèmes se posent à moi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 enum RequiredData { /* ... */ }; struct Task { Task () : _target (NULL), _flag (NONE) {} void (*execute) (Session *, string); Session * _target; string _data; RequiredData _flag; };
- Mon bind n'est pas accepté dans ThreadPool::schedule (), j'ai les erreurs suivantes :
C'est assez imbuvable et surtout incompréhensible ...In instantiation of 'boost::_bi::result_traits<boost::_bi::unspecified, void (* Task::*)(Session*, std::string)>':
instantiated from 'boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >'
error: 'void (* Task::*)(Session*, std::string)' is not a class, struct, or union type
In member function 'void boost::asio::io_service::post(const CompletionHandler&) [with CompletionHandler = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]':
error: no match for call to '(boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >) ()'
In function 'void boost::asio::asio_handler_invoke(Function, ...) [with Function = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]':
C:\boost\boost_1_47_0/boost/asio/detail/handler_invoke_helpers.hpp:39: instantiated from 'void boost_asio_handler_invoke_helpers::invoke(Function&, Context&) [with Function = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, Context = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
C:\boost\boost_1_47_0/boost/asio/detail/completion_handler.hpp:66: instantiated from 'static void boost::asio::detail::completion_handler<Handler>::do_complete(boost::asio::detail::io_service_impl*, boost::asio::detail::operation*, boost::system::error_code, size_t) [with Handler = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
C:\boost\boost_1_47_0/boost/asio/detail/completion_handler.hpp:38: instantiated from 'boost::asio::detail::completion_handler<Handler>::completion_handler(Handler&) [with Handler = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
C:\boost\boost_1_47_0/boost/asio/detail/impl/win_iocp_io_service.hpp:66: instantiated from 'void boost::asio::detail::win_iocp_io_service::post(Handler) [with Handler = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
C:\boost\boost_1_47_0/boost/asio/impl/io_service.hpp:90: instantiated from 'void boost::asio::io_service::post(const CompletionHandler&) [with CompletionHandler = boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
C:\boost\boost_1_47_0/boost/asio/handler_invoke_hook.hpp:64: error: no match for call to '(boost::_bi::bind_t<boost::_bi::unspecified, void (* Task::*)(Session*, std::string), boost::_bi::list3<boost::_bi::value<Task*>, boost::_bi::value<Session*>, boost::_bi::value<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >) ()'
Mon deuxième problème est que j'ai une fuite mémoire après destruction de tout ce système ... Mais ça je verrais quand ça marchera correctement.
Pour le boost::bind, j'ai pourtant effectué pas mal de recherche pour avoir la bonne syntaxe, mais apparemment il ne reconnait pas mon pointeur sur fonction membre ...
Devrais-je utiliser boost::function ? Ou changer ma méthode ?
Partager