KazDragon / paradice9

Telnet Chatter in C++14
Other
8 stars 2 forks source link

Improvement: Multithreading framework #67

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
At the moment, Paradice is entirely single threaded.  Yet, there are many 
places at which concurrent behaviour could be considered.

For example, input from only one socket can be parsed at once.  In theory, all 
input from all sockets can be parsed at once, since each is independent of the 
other.

Care must be taken, however, to ensure that input and output from each socket 
happens sequentially (for example, you don't start and complete parsing new 
data from a socket before you finish parsing and complete the previous data 
from the socket).  Boost.Asio accomplishes this with "strands."

Additionally, access to the game world must be made sequential.

This is set to low priority, as there are many issues to consider.

Original issue reported on code.google.com by matthew....@gmail.com on 20 Jan 2011 at 11:51

GoogleCodeExporter commented 9 years ago
GUI Thread

Because no GUI interferes with the server logic (it receives reports from, 
rather than interacts with, the server), each GUI can be run independently from 
each other.  However, access to it needs to be serialised.  Therefore, I 
propose the following rules (most of which are already kept)

# user_interface is granted access to the window's io_service.
# All access to the is performed by the user_interface's interface.
# All those accesses' functions are performed by using an io_service strand to 
ensure that only one thread is active per GUI at a time.

Original comment by matthew....@gmail.com on 21 Jul 2011 at 8:44

GoogleCodeExporter commented 9 years ago
Accomplished a lot using strands.  Added a new runtime option "-t <threads>" 
which specifies the size of the thread pool.  "Works", although there are 
undoubtedly a few race conditions peppered around.  The most obvious of these 
should be hammered out before showtime.

Original comment by matthew....@gmail.com on 31 Jan 2012 at 11:06

GoogleCodeExporter commented 9 years ago
Observed a crash when a player was logging in.

Original comment by matthew....@gmail.com on 19 Mar 2012 at 11:03

GoogleCodeExporter commented 9 years ago
There may yet be issues between the IO and GUI strands of different clients.

For example, if a client logs in or out, then a message is broadcast to all 
players.  This broadcast could occur while another client is busy updating its 
GUI.  Since there is no locking in place, this could conceivably cause a 
vector<> (say) to be reallocated while it is being read.

I suggest one of two strategies:
  * All changes to GUI structures are scheduled on the GUI strand for that client.
  * All changes to GUI structures are synchronised with locks.

The former is a more ideal solution, since it enables a lot of task parallelism 
off the bat.  E.g. a broadcast message such as above is simply strand.post()ed 
to each client rather than locking each client sequentially (yes, this could be 
parallelised at the source, but that's far more work than using strand.post()).

However, it's difficult to ship a client's GUI strand to *all* GUI components.  
Therefore, the latter solution is the more simple solution.

Original comment by matthew....@gmail.com on 21 Jun 2012 at 8:28

GoogleCodeExporter commented 9 years ago
After some investigation, the above comment is somewhat obsolete.  The 
hugin::user_interface class already dispatches requests to add output text on 
the client's GUI strand.

Original comment by matthew....@gmail.com on 21 Jun 2012 at 9:26

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
The log-in crash seems to be due to timing issues between connecting, detecting 
the terminal type, and constructing and displaying the UI.

Original comment by matthew....@gmail.com on 22 Jun 2012 at 12:02

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
This may rely on/provide the basis for Issue #99, since the main multithreading 
issue seems to be at log-on time: there appear to be race conditions between 
setting up the UI and detecting the terminal type.  Fully separating the two 
would go a long way to sorting both these issues out.

Original comment by matthew....@gmail.com on 27 Jun 2012 at 7:27

GoogleCodeExporter commented 9 years ago
A good tool for detecting data races is valgrind, using --tool=drd (data race 
detector) or --tool=helgrind.  It looks to highlight a number of potential 
issues, some of which may require quite some low-level redesign.

Original comment by matthew....@gmail.com on 9 Oct 2012 at 7:21

GoogleCodeExporter commented 9 years ago
Helgrind shows the following:

==16604== Possible data race during read of size 4 at 0x4302b18 by thread #2
==16604==    at 0x80F8677: munin::basic_container::do_layout() 
(basic_container.cpp:1049)
==16604==    by 0x814AD0B: munin::window::impl::do_layout() (window.cpp:717)
==16604==    by 0x8147DF2: 
boost::asio::detail::completion_handler<boost::_bi::bind_t<void, 
boost::_mfi::mf0<void, munin::window::impl>, 
boost::_bi::list1<boost::_bi::value<boost::shared_ptr<munin::window::impl> > > 
> >::do_complete(boost::asio::detail::task_io_service*, 
boost::asio::detail::task_io_service_operation*, boost::system::error_code 
const&, unsigned int) (mem_fn_template.hpp:40)
==16604==    by 0x8059B7B: 
boost::asio::detail::strand_service::do_complete(boost::asio::detail::task_io_se
rvice*, boost::asio::detail::task_io_service_operation*, 
boost::system::error_code const&, unsigned int) 
(task_io_service_operation.hpp:37)
==16604==    by 0x80727D9: 
boost::asio::detail::task_io_service::run(boost::system::error_code&) 
(task_io_service_operation.hpp:37)
==16604==    by 0x8062122: run_io_service(boost::asio::io_service&) 
(io_service.ipp:59)
==16604==    by 0x81EF08B: thread_proxy (in 
/home/mach/code/para/paradice9/paradice.exe)
==16604==    by 0x4026F60: mythread_wrapper (hg_intercepts.c:221)
==16604==    by 0x404EE98: start_thread (pthread_create.c:304)
==16604==    by 0x42619ED: clone (clone.S:130)
==16604==  This conflicts with a previous write of size 4 by thread #3
==16604==    at 0x80FDB16: std::vector<boost::shared_ptr<munin::component>, 
std::allocator<boost::shared_ptr<munin::component> > 
>::_M_insert_aux(__gnu_cxx::__normal_iterator<boost::shared_ptr<munin::component
>*, std::vector<boost::shared_ptr<munin::component>, 
std::allocator<boost::shared_ptr<munin::component> > > >, 
boost::shared_ptr<munin::component> const&) (vector.tcc:364)
==16604==    by 0x80FAE0F: 
munin::basic_container::do_add_component(boost::shared_ptr<munin::component> 
const&, boost::any const&, unsigned int) (stl_vector.h:749)
==16604==    by 0x811311E: 
munin::container::add_component(boost::shared_ptr<munin::component> const&, 
boost::any const&, unsigned int) (container.cpp:188)
==16604==    by 0x807F25E: 
paradice::client::impl::set_connection(boost::shared_ptr<paradice::connection>) 
(client.cpp:258)
==16604==    by 0x8075150: 
paradice::client::set_connection(boost::shared_ptr<paradice::connection> 
const&) (client.cpp:985)
==16604==    by 0x8060510: 
paradice9::impl::on_terminal_type(boost::weak_ptr<odin::net::socket>, 
boost::weak_ptr<paradice::connection>, std::string const&) (paradice9.cpp:139)
==16604==    by 0x805D00C: 
boost::detail::function::void_function_obj_invoker1<boost::_bi::bind_t<void, 
boost::_mfi::mf3<void, paradice9::impl, boost::weak_ptr<odin::net::socket>, 
boost::weak_ptr<paradice::connection>, std::string const&>, 
boost::_bi::list4<boost::_bi::value<paradice9::impl*>, 
boost::_bi::value<boost::weak_ptr<odin::net::socket> >, 
boost::_bi::value<boost::weak_ptr<paradice::connection> >, boost::arg<1> > >, 
void, std::string>::invoke(boost::detail::function::function_buffer&, 
std::string) (mem_fn_template.hpp:393)
==16604==    by 0x808E5CC: paradice::connection::impl::announce_terminal_type() 
(function_template.hpp:760)

In short, whereas the first call chain is protected by a strand, the second 
(from client::set_connection down) is not.  This may be the cause of one of the 
primary MT problems.

Original comment by matthew....@gmail.com on 15 Oct 2012 at 12:59

GoogleCodeExporter commented 9 years ago
Confirmed -- at first glance, thunking set_connection out to be dispatched on 
the GUI strand removes this error.

Original comment by matthew....@gmail.com on 15 Oct 2012 at 1:10

GoogleCodeExporter commented 9 years ago

Original comment by matthew....@gmail.com on 5 Sep 2013 at 11:52

GoogleCodeExporter commented 9 years ago
I just ran Paradice with Clang's thread sanitizer (-fsanitize=thread), and the 
output from just one client logging in indicates that there's a lot to clean 
up.  This may require some serious restructuring post-C++11 conversion.

Here's the very first data race.

WARNING: ThreadSanitizer: data race (pid=20450)
  Read of size 1 at 0x7d080000d3cc by thread T1:
    #0 void boost::asio::detail::reactive_socket_service_base::async_send<boost::asio::mutable_buffers_1, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > >(boost::asio::detail::reactive_socket_service_base::base_implementation_type&, boost::asio::mutable_buffers_1 const&, int, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >) <null>:0 (paradice.exe+0x0000003f28a5)
    #1 boost::asio::async_result<boost::asio::handler_type<boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >, void (boost::system::error_code, unsigned long)>::type>::type boost::asio::stream_socket_service<boost::asio::ip::tcp>::async_send<boost::asio::mutable_buffers_1, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > >(boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>::implementation_type&, boost::asio::mutable_buffers_1 const&, int, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > const&) <null>:0 (paradice.exe+0x0000003f253b)
    #2 boost::asio::async_result<boost::asio::handler_type<boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> >, void (boost::system::error_code, unsigned long)>::type>::type boost::asio::async_write<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >(boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&, boost::asio::mutable_buffers_1 const&, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > const&) <null>:0 (paradice.exe+0x0000003f186e)
    #3 odin::net::socket::impl::write_first_request() <null>:0 (paradice.exe+0x0000003f151c)
    #4 odin::net::socket::impl::async_write(std::vector<unsigned char, std::allocator<unsigned char> > const&, boost::function<void (unsigned long)> const&) <null>:0 (paradice.exe+0x0000003efaf5)
    #5 non-virtual thunk to odin::net::socket::async_write(std::vector<unsigned char, std::allocator<unsigned char> > const&, boost::function<void (unsigned long)> const&) <null>:0 (paradice.exe+0x0000003ee5ef)
    #6 odin::telnet::stream::impl::check_async_write_requests() <null>:0 (paradice.exe+0x0000004096f7)
    #7 void boost::asio::asio_handler_invoke<boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > > >(boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > >, ...) <null>:0 (paradice.exe+0x0000004176bb)
    #8 boost::asio::detail::completion_handler<boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) <null>:0 (paradice.exe+0x0000004173d6)
    #9 boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) <null>:0 (paradice.exe+0x00000023c167)
    #10 boost::asio::detail::task_io_service::run(boost::system::error_code&) <null>:0 (paradice.exe+0x00000023b62f)
    #11 run_io_service(boost::asio::io_service&) <null>:0 (paradice.exe+0x00000021de7d)
    #12 boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(boost::asio::io_service&), boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > > >::run() <null>:0 (paradice.exe+0x0000002213d9)
    #13 thread_proxy <null>:0 (libboost_thread.so.1.54.0+0x00000000c279)

  Previous write of size 1 at 0x7d080000d3cc by thread T7:
    #0 boost::asio::detail::reactive_socket_service_base::start_op(boost::asio::detail::reactive_socket_service_base::base_implementation_type&, int, boost::asio::detail::reactor_op*, bool, bool, bool) <null>:0 (paradice.exe+0x0000003f2af2)
    #1 void boost::asio::detail::reactive_socket_service_base::async_receive<boost::asio::mutable_buffers_1, boost::asio::detail::read_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > >(boost::asio::detail::reactive_socket_service_base::base_implementation_type&, boost::asio::mutable_buffers_1 const&, int, boost::asio::detail::read_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >) <null>:0 (paradice.exe+0x0000003f4dd5)
    #2 boost::asio::async_result<boost::asio::handler_type<boost::asio::detail::read_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >, void (boost::system::error_code, unsigned long)>::type>::type boost::asio::stream_socket_service<boost::asio::ip::tcp>::async_receive<boost::asio::mutable_buffers_1, boost::asio::detail::read_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > >(boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>::implementation_type&, boost::asio::mutable_buffers_1 const&, int, boost::asio::detail::read_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > const&) <null>:0 (paradice.exe+0x0000003f49bb)
    #3 boost::asio::async_result<boost::asio::handler_type<boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> >, void (boost::system::error_code, unsigned long)>::type>::type boost::asio::async_read<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >(boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&, boost::asio::mutable_buffers_1 const&, boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > const&) <null>:0 (paradice.exe+0x0000003f3d0e)
    #4 odin::net::socket::impl::async_read(unsigned long, boost::function<void (std::vector<unsigned char, std::allocator<unsigned char> >)> const&) <null>:0 (paradice.exe+0x0000003ef4fd)
    #5 odin::net::socket::async_read(unsigned long, boost::function<void (std::vector<unsigned char, std::allocator<unsigned char> >)> const&) <null>:0 (paradice.exe+0x0000003ee36f)
    #6 odin::telnet::stream::impl::check_async_read_requests() <null>:0 (paradice.exe+0x0000004184fe)
    #7 void boost::asio::asio_handler_invoke<boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > > >(boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > >, ...) <null>:0 (paradice.exe+0x0000004176bb)
    #8 boost::asio::detail::completion_handler<boost::_bi::bind_t<void, boost::_mfi::mf0<void, odin::telnet::stream::impl>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<odin::telnet::stream::impl> > > > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) <null>:0 (paradice.exe+0x0000004173d6)
    #9 boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) <null>:0 (paradice.exe+0x00000023c167)
    #10 boost::asio::detail::task_io_service::run(boost::system::error_code&) <null>:0 (paradice.exe+0x00000023b62f)
    #11 run_io_service(boost::asio::io_service&) <null>:0 (paradice.exe+0x00000021de7d)
    #12 boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(boost::asio::io_service&), boost::_bi::list1<boost::reference_wrapper<boost::asio::io_service> > > >::run() <null>:0 (paradice.exe+0x0000002213d9)
    #13 thread_proxy <null>:0 (libboost_thread.so.1.54.0+0x00000000c279)

  Location is heap block of size 32 at 0x7d080000d3c0 allocated by main thread:
    #0 operator new(unsigned long) /home/chaplain/code/llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:560 (paradice.exe+0x000000194479)
    #1 odin::net::server::impl::schedule_accept() <null>:0 (paradice.exe+0x0000003e905a)
    #2 odin::net::server::server(boost::asio::io_service&, unsigned short, boost::function<void (boost::shared_ptr<odin::net::socket>)> const&) <null>:0 (paradice.exe+0x0000003e8a28)
    #3 paradice9::impl::impl(boost::asio::io_service&, boost::shared_ptr<boost::asio::io_service::work>, unsigned int) <null>:0 (paradice.exe+0x0000002127a6)
    #4 paradice9::paradice9(boost::asio::io_service&, boost::shared_ptr<boost::asio::io_service::work>, unsigned int) <null>:0 (paradice.exe+0x0000002124cd)
    #5 main <null>:0 (paradice.exe+0x00000021cbb9)

  Thread T1 (tid=20454, running) created by main thread at:
    #0 pthread_create /home/chaplain/code/llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:877 (paradice.exe+0x00000019812b)
    #1 boost::thread::start_thread_noexcept() <null>:0 (libboost_thread.so.1.54.0+0x00000000bdf6)
    #2 boost::thread::thread<void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> >(void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service>, boost::disable_if<boost::thread_detail::is_convertible<void (*&)(boost::asio::io_service&), boost::thread_attributes>, boost::thread::dummy*>::type) <null>:0 (paradice.exe+0x000000220405)
    #3 boost::detail::sp_if_not_array<boost::thread>::type boost::make_shared<boost::thread, void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> >(void (* const&)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> const&) <null>:0 (paradice.exe+0x00000021f350)
    #4 main <null>:0 (paradice.exe+0x00000021cc7b)

  Thread T7 (tid=20460, running) created by main thread at:
    #0 pthread_create /home/chaplain/code/llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:877 (paradice.exe+0x00000019812b)
    #1 boost::thread::start_thread_noexcept() <null>:0 (libboost_thread.so.1.54.0+0x00000000bdf6)
    #2 boost::thread::thread<void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> >(void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service>, boost::disable_if<boost::thread_detail::is_convertible<void (*&)(boost::asio::io_service&), boost::thread_attributes>, boost::thread::dummy*>::type) <null>:0 (paradice.exe+0x000000220405)
    #3 boost::detail::sp_if_not_array<boost::thread>::type boost::make_shared<boost::thread, void (*)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> >(void (* const&)(boost::asio::io_service&), boost::reference_wrapper<boost::asio::io_service> const&) <null>:0 (paradice.exe+0x00000021f350)
    #4 main <null>:0 (paradice.exe+0x00000021cc7b)

SUMMARY: ThreadSanitizer: data race ??:0 void 
boost::asio::detail::reactive_socket_service_base::async_send<boost::asio::mutab
le_buffers_1, 
boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::
tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, 
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, 
boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, 
boost::system::error_code const&, unsigned long>, 
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<odin::net::socket::impl> 
>, boost::arg<1> (*)(), boost::arg<2> (*)()> > > 
>(boost::asio::detail::reactive_socket_service_base::base_implementation_type&, 
boost::asio::mutable_buffers_1 const&, int, 
boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::
tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, 
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, 
boost::_bi::bind_t<void, boost::_mfi::mf2<void, odin::net::socket::impl, boost::

Original comment by matthew....@gmail.com on 2 Dec 2013 at 8:01