2017-12-01 14 views
1

asio :: ip :: tcp :: socket에 일련의 중첩 비동기 작업이 있으며 가능한 한 빨리 중지 할 수있는 가능성이 필요합니다. 다른 스레드.소켓에서 향후의 비동기 작업을 취소하거나 올바르게 차단하십시오.

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 
     }); 
    }); 
}); 

문제는 간단한 socket->cancel() 호출이 늘 항상 콜백 중 하나가 실행 중일 수 있습니다 호출의 순간에 있기 때문에 일을한다는 것입니다 : 는 여기에 몇 가지 의사입니다. 따라서 취소 할 대기열에 포함 된 작업은 없지만 실행중인 콜백은 곧 추가하고 순서를 계속할 수 있습니다. socket->cancel() 이후에도 비동기 작업을 취소하고 싶습니다 (즉각 operation_aborted 오류로 완료).

유일한 생각은 어떻게 든 취소 플래그

//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(); 

에게 mutex.lock()에서 모든 호출을 래핑하고 사용하는 것입니다 그러나 그것은 끔찍한 보인다.
io_service::strand에 대해 들어 본 적이 있지만 여기에서 사용하는 방법을 모르십니까? socket->cancel() 방법으로 .post()를 사용 하시겠습니까? {콜백, 취소, 콜백} 상황이 불가능하다는 보장이 있습니까?

답변

0

{콜백, 취소, 콜백} 항상 가능합니다. 피하려고하는 것이 아닙니다. 사실, 취소는 항상으로 보류중인 작업이 완료되므로 적어도 작업에 대한 콜백이 있습니다 (작업이 중단되었음을 나타내는 오류 코드와 함께).

당신은 소켓이 "취소"했다 알면합니다 (그렇게하지 않는 작업을 취소 : 그것은 작업하지 소켓 취소) 새 작업 일정입니다 을 피하기 위해 당신이 원하는/필요.

영구적으로
  1. 당신은 소켓과의 모든 작업을 종료하려면,

    I 좋겠 단순히 게시물 :

    나는 사람이 당신이 원하는 것을 할 수있는 상황에 따라 두 가지 참조 소켓을 닫는 작업 (물론 보류중인 작업을 취소합니다). 이점은 실수로 소켓에 대한 새 작업을 예약하기 전에 소켓 상태 [sock.is_open] http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/basic_stream_socket/is_open.html을 확인할 수 있다는 것입니다. 이 서비스를 -ning 여러 스레드 run이 IFF에

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

    당신은 sock 변수를 액세스하는 데이터 레이스를 피하기 위해 가닥이 필요합니다. 당신은 소켓 open¹를 떠나 특정 작동 체인을 취소하려면 Why do I need strand per connection when using boost::asio?

  2. 를 참조하십시오, 당신은 작업이 취소 된 때를 나타내는 각 소켓과 플래그를 가질 수있다. 이미 것이다 참여

    모두 완료 핸들러는 error_code 포함 boost::asio::error::operation_aborted은 그래서 그 체인의 "후속"일을 피하기 위해 정말 쉽게해야받을 수 있습니다.

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

    사실은 대부분의 오류에 그 작업을 수행 할 수 있습니다 :

    그냥 콜백 람다 헤더에 이런 일을했습니다.

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

    플래그는 일부 다른 스레드가 새로운 독립 비동기 작업 (체인)을 게시 할 수 막 있다면 단지 유리하고 그렇지 않으면 솔루션을 사용, 소켓을 닫지 않고도 (다시 차단하려면 #1).

    sock을 아직 공유하지 않은 사용자와 공유하지 않기 때문에 해당 소켓에서 동기화가 필요하지 않습니다. sock도 스레드로부터 안전하지 않으므로 플래그 액세스가 안전해야합니다.

    다시 말하지만, 사실이 아니라면 처음부터 시작해야했습니다.

    >

    하나의 서비스 쓰레드는 암시 가닥을 의미하는 데, 당신은 결코 직접 비동기 작업을 게시하지하여이 작업을 게시 많은 스레드가있을 수 있습니다에도 불구하고 복잡성을 피할 수 있습니다 :

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

    이렇게하면 모든 소켓 작업이 암시 적으로 이루어집니다.


는 사실이 이해 할 수있는 프로토콜을 생각할 수 없다 ¹, 그러나 아마 데이터 그램 프로토콜 (?)

+0

* "나는 단순히 작업을 게시 할 것 소켓을 닫습니다 "* 예, 필요한 것 같습니다. 하지만 상황이 (스트랜드 콜백이 끝나고, 새로운 데이터가 소켓에 도착하고, 새로운 콜백이 스트링에 대기하며, 닫는 스레드는 close() 메소드를 대기열에 포함시킵니다.) 불가능합니다. – Acuion

+0

혼란스러워. 콜백은 데이터가 도착할 때 "자발적으로 대기열에 넣기"하지 않습니다. 먼저 해당 작업에 게시 할 작업을 _ 필요합니다. 나는 당신이 무엇을 물어보고 싶어하는지 알 수 없다. – sehe