Revert previous change that allowed some operations to be performed without
holding the lock, as it introduced a race condition in certain multithreaded
scenarios.
diff --git a/asio/include/asio/detail/epoll_reactor.hpp b/asio/include/asio/detail/epoll_reactor.hpp
index 6d685f8..b30f191 100644
--- a/asio/include/asio/detail/epoll_reactor.hpp
+++ b/asio/include/asio/detail/epoll_reactor.hpp
@@ -55,8 +55,6 @@
     descriptor_state* next_;
     descriptor_state* prev_;
 
-    bool op_queue_is_empty_[max_ops];
-
     mutex mutex_;
     epoll_reactor* reactor_;
     int descriptor_;
diff --git a/asio/include/asio/detail/impl/epoll_reactor.ipp b/asio/include/asio/detail/impl/epoll_reactor.ipp
index 859e284..bd60515 100644
--- a/asio/include/asio/detail/impl/epoll_reactor.ipp
+++ b/asio/include/asio/detail/impl/epoll_reactor.ipp
@@ -155,10 +155,6 @@
     descriptor_data->reactor_ = this;
     descriptor_data->descriptor_ = descriptor;
     descriptor_data->shutdown_ = false;
-
-    for (int i = 0; i < max_ops; ++i)
-      descriptor_data->op_queue_is_empty_[i] =
-        descriptor_data->op_queue_[i].empty();
   }
 
   epoll_event ev = { 0, { 0 } };
@@ -184,10 +180,6 @@
     descriptor_data->descriptor_ = descriptor;
     descriptor_data->shutdown_ = false;
     descriptor_data->op_queue_[op_type].push(op);
-
-    for (int i = 0; i < max_ops; ++i)
-      descriptor_data->op_queue_is_empty_[i] =
-        descriptor_data->op_queue_[i].empty();
   }
 
   epoll_event ev = { 0, { 0 } };
@@ -219,22 +211,6 @@
     return;
   }
 
-  bool perform_speculative = allow_speculative;
-  if (perform_speculative)
-  {
-    if (descriptor_data->op_queue_is_empty_[op_type]
-        && (op_type != read_op
-          || descriptor_data->op_queue_is_empty_[except_op]))
-    {
-      if (op->perform())
-      {
-        io_service_.post_immediate_completion(op);
-        return;
-      }
-      perform_speculative = false;
-    }
-  }
-
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
   if (descriptor_data->shutdown_)
@@ -243,17 +219,11 @@
     return;
   }
 
-  for (int i = 0; i < max_ops; ++i)
-    descriptor_data->op_queue_is_empty_[i] =
-      descriptor_data->op_queue_[i].empty();
-
-  if (descriptor_data->op_queue_is_empty_[op_type])
+  if (descriptor_data->op_queue_[op_type].empty())
   {
     if (allow_speculative)
     {
-      if (perform_speculative
-          && (op_type != read_op
-            || descriptor_data->op_queue_is_empty_[except_op]))
+      if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
       {
         if (op->perform())
         {
@@ -274,7 +244,6 @@
   }
 
   descriptor_data->op_queue_[op_type].push(op);
-  descriptor_data->op_queue_is_empty_[op_type] = false;
   io_service_.work_started();
 }
 
diff --git a/asio/include/asio/detail/impl/kqueue_reactor.ipp b/asio/include/asio/detail/impl/kqueue_reactor.ipp
index 3a9cf01..209f367 100644
--- a/asio/include/asio/detail/impl/kqueue_reactor.ipp
+++ b/asio/include/asio/detail/impl/kqueue_reactor.ipp
@@ -132,10 +132,6 @@
   descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
 
-  for (int i = 0; i < max_ops; ++i)
-    descriptor_data->op_queue_is_empty_[i] =
-      descriptor_data->op_queue_[i].empty();
-
   return 0;
 }
 
@@ -151,10 +147,6 @@
   descriptor_data->shutdown_ = false;
   descriptor_data->op_queue_[op_type].push(op);
 
-  for (int i = 0; i < max_ops; ++i)
-    descriptor_data->op_queue_is_empty_[i] =
-      descriptor_data->op_queue_[i].empty();
-
   struct kevent event;
   switch (op_type)
   {
@@ -195,21 +187,6 @@
     return;
   }
 
-  if (allow_speculative)
-  {
-    if (descriptor_data->op_queue_is_empty_[op_type]
-        && (op_type != read_op
-          || descriptor_data->op_queue_is_empty_[except_op]))
-    {
-      if (op->perform())
-      {
-        io_service_.post_immediate_completion(op);
-        return;
-      }
-      allow_speculative = false;
-    }
-  }
-
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
   if (descriptor_data->shutdown_)
@@ -218,16 +195,12 @@
     return;
   }
 
-  for (int i = 0; i < max_ops; ++i)
-    descriptor_data->op_queue_is_empty_[i] =
-      descriptor_data->op_queue_[i].empty();
-
-  bool first = descriptor_data->op_queue_is_empty_[op_type];
+  bool first = descriptor_data->op_queue_[op_type].empty();
   if (first)
   {
     if (allow_speculative)
     {
-      if (op_type != read_op || descriptor_data->op_queue_is_empty_[except_op])
+      if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
       {
         if (op->perform())
         {
@@ -240,7 +213,6 @@
   }
 
   descriptor_data->op_queue_[op_type].push(op);
-  descriptor_data->op_queue_is_empty_[op_type] = false;
   io_service_.work_started();
 
   if (first)
diff --git a/asio/include/asio/detail/kqueue_reactor.hpp b/asio/include/asio/detail/kqueue_reactor.hpp
index e420f63..533868c 100644
--- a/asio/include/asio/detail/kqueue_reactor.hpp
+++ b/asio/include/asio/detail/kqueue_reactor.hpp
@@ -65,8 +65,6 @@
     descriptor_state* next_;
     descriptor_state* prev_;
 
-    bool op_queue_is_empty_[max_ops];
-
     mutex mutex_;
     int descriptor_;
     op_queue<reactor_op> op_queue_[max_ops];