asio implizite Strang- und Datensynchronisation

Wenn ich asio-Quellcode lese, bin ich neugierig, wie asio Daten zwischen Threads synchronisiert, selbst wenn ein impliziter Strang erstellt wurde. Dies sind Code in Asio:

io_service :: run

 mutex::scoped_lock lock(mutex_);

  std::size_t n = 0;
  for (; do_run_one(lock, this_thread, ec); lock.lock())
    if (n != (std::numeric_limits<std::size_t>::max)())
      ++n;
  return n;

io_service :: do_run_one

 while (!stopped_)
  {
    if (!op_queue_.empty())
    {
      // Prepare to execute first handler from queue.
      operation* o = op_queue_.front();
      op_queue_.pop();
      bool more_handlers = (!op_queue_.empty());

      if (o == &task_operation_)
      {
        task_interrupted_ = more_handlers;

        if (more_handlers && !one_thread_)
        {
          if (!wake_one_idle_thread_and_unlock(lock))
            lock.unlock();
        }
        else
          lock.unlock();

        task_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Run the task. May throw an exception. Only block if the operation
        // queue is empty and we're not polling, otherwise we want to return
        // as soon as possible.
        task_->run(!more_handlers, this_thread.private_op_queue);
      }
      else
      {
        std::size_t task_result = o->task_result_;

        if (more_handlers && !one_thread_)
          wake_one_thread_and_unlock(lock);
        else
          lock.unlock();

        // Ensure the count of outstanding work is decremented on block exit.
        work_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Complete the operation. May throw an exception. Deletes the object.
        o->complete(*this, ec, task_result);

        return 1;
      }
    }

In seinem do_run_one werden alle Unlock-Befehle von Mutex ausgeführt, bevor der Handler ausgeführt wird. Wenn es einen impliziten Strang gibt, wird der Handler nicht gleichzeitig ausgeführt, aber das Problem ist: Thread A führt einen Handler aus, der Daten ändert, und Thread B führt den nächsten Handler aus, der die Daten liest, die von Thread A geändert wurden. Ohne den Schutz von Mutex , wie Thread B die von Thread A vorgenommenen Datenänderungen gesehen hat? Durch das Entsperren des Mutex vor der Ausführung des Handlers wird keine Beziehung hergestellt, bevor Threads auf die Daten zugreifen, auf die der Handler zugegriffen hat. Wenn ich weiter gehe, verwendet die Handlerausführung ein Ding namens fenced_block:

 completion_handler* h(static_cast<completion_handler*>(base));
    ptr p = { boost::addressof(h->handler_), h, h };

    BOOST_ASIO_HANDLER_COMPLETION((h));

    // Make a copy of the handler so that the memory can be deallocated before
    // the upcall is made. Even if we're not about to make an upcall, a
    // sub-object of the handler may be the true owner of the memory associated
    // with the handler. Consequently, a local copy of the handler is required
    // to ensure that any owning sub-object remains valid until after we have
    // deallocated the memory here.
    Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_));
    p.h = boost::addressof(handler);
    p.reset();

    // Make the upcall if required.
    if (owner)
    {
      fenced_block b(fenced_block::half);
      BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
      boost_asio_handler_invoke_helpers::invoke(handler, handler);
      BOOST_ASIO_HANDLER_INVOCATION_END;
    }

Was ist das? Ich weiß, Zaun scheint ein Sync-Primitiv zu sein, das von C ++ 11 unterstützt wird, aber dieser Zaun wird vollständig von Asio selbst geschrieben. Hilft dieser Fenced_Block bei der Datensynchronisation?

AKTUALISIERTE

Nachdem ich google und lesediese unddiese, asio benutze in der Tat das Memory Fence Primitive, um Daten in Threads zu synchronisieren, das ist schneller als das Entsperren, bis der Handler die Ausführung abgeschlossen hatGeschwindigkeitsunterschied auf x86). Tatsächlich wird das flüchtige Java-Schlüsselwort implementiert, indem nach dem Schreiben und vor dem Lesen dieser Variablen eine Speichersperre eingefügt wird, um eine Beziehung zwischen dem Ereignis und dem Ereignis herzustellen.

Wenn jemand einfach die Implementierung eines Asio-Speicherzauns beschreiben oder etwas hinzufügen könnte, das ich verpasst oder missverstanden habe, werde ich dies akzeptieren.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage