Fix potential strand starvation issue that can occur when strand.post() is used.
diff --git a/asio/include/asio/detail/impl/strand_service.hpp b/asio/include/asio/detail/impl/strand_service.hpp
index a626682..ec7008a 100644
--- a/asio/include/asio/detail/impl/strand_service.hpp
+++ b/asio/include/asio/detail/impl/strand_service.hpp
@@ -28,7 +28,7 @@
 
 inline strand_service::strand_impl::strand_impl()
   : operation(&strand_service::do_complete),
-    count_(0)
+    locked_(false)
 {
 }
 
@@ -40,7 +40,8 @@
   ~on_dispatch_exit()
   {
     impl_->mutex_.lock();
-    bool more_handlers = (--impl_->count_ > 0);
+    impl_->ready_queue_.push(impl_->waiting_queue_);
+    bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
     impl_->mutex_.unlock();
 
     if (more_handlers)
diff --git a/asio/include/asio/detail/impl/strand_service.ipp b/asio/include/asio/detail/impl/strand_service.ipp
index 4d05ad5..d89554d 100644
--- a/asio/include/asio/detail/impl/strand_service.ipp
+++ b/asio/include/asio/detail/impl/strand_service.ipp
@@ -32,7 +32,8 @@
   ~on_do_complete_exit()
   {
     impl_->mutex_.lock();
-    bool more_handlers = (--impl_->count_ > 0);
+    impl_->ready_queue_.push(impl_->waiting_queue_);
+    bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
     impl_->mutex_.unlock();
 
     if (more_handlers)
@@ -55,8 +56,13 @@
   asio::detail::mutex::scoped_lock lock(mutex_);
 
   for (std::size_t i = 0; i < num_implementations; ++i)
+  {
     if (strand_impl* impl = implementations_[i].get())
-      ops.push(impl->queue_);
+    {
+      ops.push(impl->waiting_queue_);
+      ops.push(impl->ready_queue_);
+    }
+  }
 }
 
 void strand_service::construct(strand_service::implementation_type& impl)
@@ -80,41 +86,55 @@
 
 bool strand_service::do_dispatch(implementation_type& impl, operation* op)
 {
-  // If we are running inside the io_service, and no other handler is queued
-  // or running, then the handler can run immediately.
+  // If we are running inside the io_service, and no other handler already
+  // holds the strand lock, then the handler can run immediately.
   bool can_dispatch = io_service_.can_dispatch();
   impl->mutex_.lock();
-  bool first = (++impl->count_ == 1);
-  if (can_dispatch && first)
+  if (can_dispatch && !impl->locked_)
   {
     // Immediate invocation is allowed.
+    impl->locked_ = true;
     impl->mutex_.unlock();
     return true;
   }
 
-  // Immediate invocation is not allowed, so enqueue for later.
-  impl->queue_.push(op);
-  impl->mutex_.unlock();
-
-  // The first handler to be enqueued is responsible for scheduling the
-  // strand.
-  if (first)
+  if (impl->locked_)
+  {
+    // Some other handler already holds the strand lock. Enqueue for later.
+    impl->waiting_queue_.push(op);
+    impl->mutex_.unlock();
+  }
+  else
+  {
+    // The handler is acquiring the strand lock and so is responsible for
+    // scheduling the strand.
+    impl->locked_ = true;
+    impl->mutex_.unlock();
+    impl->ready_queue_.push(op);
     io_service_.post_immediate_completion(impl);
+  }
 
   return false;
 }
 
 void strand_service::do_post(implementation_type& impl, operation* op)
 {
-  // Add the handler to the queue.
   impl->mutex_.lock();
-  bool first = (++impl->count_ == 1);
-  impl->queue_.push(op);
-  impl->mutex_.unlock();
-
-  // The first handler to be enqueue is responsible for scheduling the strand.
-  if (first)
+  if (impl->locked_)
+  {
+    // Some other handler already holds the strand lock. Enqueue for later.
+    impl->waiting_queue_.push(op);
+    impl->mutex_.unlock();
+  }
+  else
+  {
+    // The handler is acquiring the strand lock and so is responsible for
+    // scheduling the strand.
+    impl->locked_ = true;
+    impl->mutex_.unlock();
+    impl->ready_queue_.push(op);
     io_service_.post_immediate_completion(impl);
+  }
 }
 
 void strand_service::do_complete(io_service_impl* owner, operation* base,
@@ -124,12 +144,6 @@
   {
     strand_impl* impl = static_cast<strand_impl*>(base);
 
-    // Get the next handler to be executed.
-    impl->mutex_.lock();
-    operation* o = impl->queue_.front();
-    impl->queue_.pop();
-    impl->mutex_.unlock();
-
     // Indicate that this strand is executing on the current thread.
     call_stack<strand_impl>::context ctx(impl);
 
@@ -137,7 +151,13 @@
     on_do_complete_exit on_exit = { owner, impl };
     (void)on_exit;
 
-    o->complete(*owner, ec, 0);
+    // Run all ready handlers. No lock is required since the ready queue is
+    // accessed only within the strand.
+    while (operation* o = impl->ready_queue_.front())
+    {
+      impl->ready_queue_.pop();
+      o->complete(*owner, ec, 0);
+    }
   }
 }
 
diff --git a/asio/include/asio/detail/strand_service.hpp b/asio/include/asio/detail/strand_service.hpp
index 6cb97d5..82aab3f 100644
--- a/asio/include/asio/detail/strand_service.hpp
+++ b/asio/include/asio/detail/strand_service.hpp
@@ -56,11 +56,20 @@
     // Mutex to protect access to internal data.
     asio::detail::mutex mutex_;
 
-    // The count of handlers in the strand, including the upcall (if any).
-    std::size_t count_;
+    // Indicates whether the strand is currently "locked" by a handler. This
+    // means that there is a handler upcall in progress, or that the strand
+    // itself has been scheduled in order to invoke some pending handlers.
+    bool locked_;
 
-    // The handlers waiting on the strand.
-    op_queue<operation> queue_;
+    // The handlers that are waiting on the strand but should not be run until
+    // after the next time the strand is scheduled. This queue must only be
+    // modified while the mutex is locked.
+    op_queue<operation> waiting_queue_;
+
+    // The handlers that are ready to be run. Logically speaking, these are the
+    // handlers that hold the strand's lock. The ready queue is only modified
+    // from within the strand and so may be accessed without locking the mutex.
+    op_queue<operation> ready_queue_;
   };
 
   typedef strand_impl* implementation_type;