2017-12-01 5 views
1

Ich habe eine Sequenz von geschachtelten asynchronen Operationen auf einem Asio :: IP :: tcp :: socket und ich möchte eine Möglichkeit haben, es so schnell wie möglich aus zu stoppen ein anderer Thread. Hier sind einige Pseudo:Abbrechen oder einfach ordnungsgemäß blockieren zukünftige asynchrone Operation auf dem Sockel

socket->async_something(buffer, CallbackLambdaHeader 
{ 
    if (errorcode) 
    { 
     //exit the sequence 
    } 
    // some code 
    socket->async_something(buffer, CallbackLambdaHeader 
    { 
     if (errorcode) 
     { 
      //exit the sequence 
     } 
     // some code 
     socket->async_something(buffer, CallbackLambdaHeader 
     { 
      if (errorcode) 
      { 
       //exit the sequence 
      } 
      // etc 
     }); 
    }); 
}); 

Das Problem ist, dass ein einfacher socket->cancel() Anruf wird nicht immer funktionieren, da im Moment des Anrufs eines der Rückrufe ausgeführt werden kann. Es wird also keine Vorgänge in der Warteschlange geben, die abgebrochen werden, aber ein laufender Rückruf kann bald einen hinzufügen und die Sequenz fortsetzen. Ich möchte die asynchronen Operationen nach socket->cancel() auch abgebrochen werden (sofort mit operation_aborted Fehler abgeschlossen).

Die einzige Idee ist irgendwie in einem mutex.lock() jeden Anruf zu wickeln und einen Aufhebungs-Flag schrecklich

//thread1: 
mutex.lock(); 
cancel = true; 
socket->cancel(); 
mutex.unlock(); 

//thread 2: 
mutex.lock(); 
if (!cancel) 
{ 
    socket->async_something(buffer, CallbackLambdaHeader 
    { 
     if (errorcode) 
     { 
      //exit the sequence 
     } 
     // some code 
     mutex.lock(); 
     if (!cancel) 
     { 
      socket->async_something(buffer, CallbackLambdaHeader 
      { 
       if (errorcode) 
       { 
        //exit the sequence 
       } 
       // some code 
       mutex.lock(); 
       if (!cancel) 
       { 
        socket->async_something(buffer, CallbackLambdaHeader 
        { 
         if (errorcode) 
         { 
          //exit the sequence 
         } 
         // etc 
        }); 
       } 
       else 
       { 
        //exit the sequence 
       } 
       mutex.unlock(); 
      }); 
     } 
     else 
     { 
      //exit the sequence 
     } 
     mutex.unlock(); 
    }); 
} 
else 
{ 
    //exit the sequence 
} 
mutex.unlock(); 

Aber es sieht verwenden.
Haben über io_service::strand gehört, aber nicht sicher, wie man es hier benutzt. Verwenden Sie .post() mit der socket->cancel() Methode? Gibt es eine Garantie, dass die Situation {Callback, Cancel, Callback} unmöglich ist?

Antwort

0

{Rückruf, Abbrechen, Rückruf} ist immer möglich, dies ist nicht das, was Sie vermeiden möchten. In der Tat wird jeder Abbruch immer in jedem ausstehenden Vorgang Abschluss führen, so wird es zumindest für diese einen Rückruf geben (mit einem Fehlercode, der angibt, dass der Vorgang abgebrochen wurde).

Was Sie wollen/müssen vermeiden, ist neue Aufgaben planen, wenn Sie die Buchse hatte „abgebrochen“ (der Löschvorgang macht das nicht: es bricht Operationen, nicht Steckdosen) kennen.

Ich sehe zwei Dinge, auf die je nach Situation könnte sein, was Sie wollen:

  1. Wenn Sie eine Steckdose und alle Operationen darauf schließen möchten, permanent

    Ich würde einfach Post eine Aufgabe, um den Socket zu schließen (was natürlich auch ausstehende Operationen abbrechen wird). Der Vorteil ist, dass Sie den Socket-Status [sock.is_open] http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_stream_socket/is_open.html) überprüfen können, bevor Sie versehentlich neue Operationen für diesen Socket einplanen.

    _service.post([this] { sock.close(); }); 
    

    Sie benötigen einen Strang zu Daten Rennen Zugriff auf die sock Variable zu vermeiden iff Sie den Dienst mehrere Threads run -ning haben. Siehe Why do I need strand per connection when using boost::asio?

  2. Wenn Sie spezifischen Betriebsketten Verlassen der Buchse open¹ abbrechen möchten, können Sie eine Flagge mit jedem Sockel haben, dass, wenn Operationen wurden abgesagt anzeigt.

    Alle Abschluss-Handler beteiligt werden bereits erhalten eine error_code enthält boost::asio::error::operation_aborted so sollte es einfach sein, zu vermeiden, in dieser Kette zu tun „Follow-up“ zu arbeiten.

    Einfach so etwas wie dies in den Callback-Lambda-Header:

    if (ec == boost::asio::error::operation_aborted) 
         return; 
    

    In dem Tun Sie wollen, dass vielleicht auf den meisten Fehler zu tun.

    if (ec) 
         return; // log `ec.message()`? 
    

    Die Flagge ist nur von Vorteil, wenn einige andere Thread gerade dabei war, eine neue unabhängige Asynchron-Betrieb zu schreiben (Kette) und Sie das auch blockieren möchten (wieder ohne die Fassung zu schließen, sonst Lösung verwenden # 1).

    Für diesen Socket ist keine Synchronisierung erforderlich, da Sie ihn nicht mit jemandem teilen, der die sock nicht bereits freigegeben hat. sock ist auch nicht Thread-sicher, so dass Sie wissen, der Zugriff auf die Flagge muss sicher sein.

    Nochmals, wenn das nicht stimmte, brauchte man zuerst einen Strang.

    >

    mit einem einzelnen Service-Thread bedeutet, dass Sie einen impliziten Strang haben, und Sie können die Komplexität vermeiden, auch wenn Sie von nie veröffentlichen asynchronen Operationen viele Threads Entsendung Aufgaben haben könnten direkt:

    _service.post([=] { if (!_sock_canceled_flag) _sock.async_something (.... 
          ); }); 
    

    Auf diese Weise sicherstellen, dass alle Socket-Operationen auf dem impliziten Strang sind.


¹ Ich kann mich eigentlich nicht ein Protokoll, in dem dieser Sinn machen könnte, aber vielleicht für einen Datagram Protocol (?)

+0

* "Ich würde einfach eine Aufgabe hinterlassen um die Steckdose zu schließen "* Ja, klingt wie, was ich brauche. Aber ist eine Situation {In-Strang-Callback endet, neue Daten kommen an den Socket, neue Callback-Enqueues an den Strang, der Closing-Thread enqueues close() -Methode} jetzt unmöglich? – Acuion

+0

Ich bin verwirrt. Callbacks werden niemals "spontan in die Warteschlange gestellt", wenn Daten eintreffen. Lies Operationen _need_, um zuerst in diesem Bereich veröffentlicht zu werden. Ich bin mir nicht sicher, was Sie sonst noch fragen könnten. – sehe

Verwandte Themen