Opened 9 years ago

Closed 8 years ago

#9203 closed Bugs (fixed)

asio::strand allocation algorithm causes handlers to execute on the wrong strand.

Reported by: Greg Barron <gregbarron71@…> Owned by: chris_kohlhoff
Milestone: To Be Determined Component: asio
Version: Boost 1.55.0 Severity: Problem
Keywords: Cc:

Description

Hi.

We recently updated from boost::asio::1.41 to boost::asio::1.53. We immediately noticed several unittests failing with socket write timeouts and initially didn't think too much of it. However after further investigation we believe that the strand implementation allocation algorithm in strand_service.ipp is the cause of these issues.

The allocation algorithm is causing deadlocks/starvation because strand_service::construct can and does provide a strand_service::implementation_type which is currently in use by another io_service::strand.

This results in handlers wrapped on io_service::strand-a being executed on io_service::strand-b. If the previous handler executing on io_service::strand-b blocks or delays the handler which should be running on io_service::strand-a will be delayed or never execute.

I have attached a sample which will demonstrate this issue:

  • Modify stand.hpp to make the members public (for debug printing).
  • Compile as 'g++ -g main.cpp -lboost_thread -lpthread -lboost_system'.
  • The example should run forever printing from the 'printer' and 'blocker'. After a little time the 'printer' will stop printing because the condition has been reached.

I have tested that it demonstrates the issue correctly in ubuntu 10.04/13.04 as well as on an ARM target (Linux (none) 2.6.35.3-dt.0.55121+ #1 Mon Dec 17 12:06:28 EST 2012 armv5tejl GNU/Linux).

The issue occurs with any version of boost from 1.42 (including trunk@86189).

This is not just a unittest issue for us. We have a TCP server accepting connections and performing async_reads/async_writes on the connection. In the same process we have another thread creating connections to the server and sending/receiving using blocking reads/writes with raw sockets (auto generated code by gSoap). Both the client and server side use strands to sequence their relative operations. Frequently the stand belonging to the connection handler on the server side is given the same implementation of the strand owned by the client side. Deadlock ensues until the client times out (20 seconds).

Attachments (1)

main.cpp (2.2 KB ) - added by Greg Barron <gregbarron71@…> 9 years ago.
Demonstrates strand allocation issue.

Download all attachments as: .zip

Change History (3)

by Greg Barron <gregbarron71@…>, 9 years ago

Attachment: main.cpp added

Demonstrates strand allocation issue.

comment:1 by anonymous, 9 years ago

Version: Boost 1.54.0Boost 1.55.0

comment:2 by chris_kohlhoff, 8 years ago

Resolution: fixed
Status: newclosed

r86464 added an additional note in the documentation to make it clearer that a strand makes no guarantee of concurrency. Included in boost 1.55.

Note: See TracTickets for help on using tickets.