문제

나는 여러 웹 페이지(온라인 상점)를 탐색하고 이러한 페이지에서 다양한 작업을 수행하는 애플리케이션을 개발하기 위해 기본적으로 비차단 I/O가 있는 Qt 프레임워크를 사용하고 있습니다.나는 이 페이지를 탐색하는 데 사용하는 상태 머신에 특정 웹 페이지를 "매핑"하고 있습니다.
이 상태 머신에는 다음과 같은 전환이 있습니다.
Connect, LogIn, Query, LogOut, Disconnect
그리고 이러한 상태;
Start, Connecting, Connected, LoggingIn, LoggedIn, Querying, QueryDone, LoggingOut, LoggedOut, Disconnecting, Disconnected
*ing에서 *ed 상태로 전환(Connecting->Connected)의 원인은 다음과 같습니다. LoadFinished 현재 요청된 URL이 로드될 때 네트워크 개체로부터 수신된 비동기 네트워크 이벤트입니다.*ed에서 *ing 상태로 전환(Connected->LoggingIn)은 제가 보낸 이벤트로 인해 발생했습니다.
이 컴퓨터에 여러 이벤트(명령)를 보낼 수 있기를 원합니다(예: Connect, LogIn, Query("productA"), Query("productB"), LogOut, LogIn, Query("productC"), LogOut, Disconnect) 한 번에 처리하도록 하세요.나 차단하고 싶지 않아 내가 보낸 모든 이벤트 처리가 컴퓨터에서 완료될 때까지 기다리는 중입니다.문제는 위에서 언급한 네트워크 이벤트와 함께 다운로드되는 URL에 대해 기계에 알리는 인터리브되어야 한다는 것입니다.인터리빙이 없으면 시스템은 상태를 발전시킬 수 없고 이벤트를 처리할 수도 없습니다. *ing에서 *ed로의 발전은 네트워크 유형의 이벤트를 수신한 후에만 발생하기 때문입니다.

디자인 목표를 어떻게 달성할 수 있나요?

편집하다

  1. 내가 사용하고 있는 상태 머신에는 자체 이벤트 루프가 있고 이벤트가 대기열에 추가되지 않으므로 머신이 사용 중일 때 이벤트가 오면 머신에서 놓칠 수 있습니다.
  2. 네트워크 I/O 이벤트는 상태 머신이나 사용 중인 이벤트 큐에 직접 게시되지 않습니다.그것들은 내 코드(처리기)에 게시되며 내가 처리해야 합니다.원하는 대로 전달할 수 있지만 번호를 기억해 두시기 바랍니다.1.
  3. 내 좀 봐 답변 이 질문에 현재 디자인을 자세히 설명했습니다.문제는 이 디자인을 만들어서 어떻게 개선할 수 있는지, 그리고 어떻게 개선할 수 있느냐는 것입니다.

    • 더욱 강력해진
    • 더 간단하다
도움이 되었습니까?

해결책

상태 머신에 이벤트 큐가 있기를 원하는 것 같습니다.이벤트를 대기열에 추가하고 첫 번째 이벤트 처리를 시작한 다음, 완료되면 다음 이벤트를 대기열에서 꺼내서 시작합니다.따라서 상태 시스템이 클라이언트 코드에 의해 직접 구동되는 대신 대기열에 의해 구동됩니다.

이는 하나의 전환 결과를 다음 전환에서 사용하는 것과 관련된 모든 논리가 머신에 있어야 함을 의미합니다.예를 들어, "로그인 완료" 페이지에서 다음에 이동할 위치를 알려주는 경우입니다.이것이 가능하지 않다면 이벤트에는 기계가 호출하여 알아야 할 모든 것을 반환할 수 있는 콜백이 포함될 수 있습니다.

다른 팁

이 질문을 하면서 나는 이미 어떤 방향으로든 대답을 왜곡하지 않기 위해 쓰고 싶지 않은 작업 디자인을 가지고 있었습니다. :) 이 의사 답변에서 내가 가진 디자인이 무엇인지 설명하겠습니다.

상태 머신 외에도 이벤트 대기열이 있습니다.이벤트를 시스템에 직접 게시하는 대신 대기열에 배치합니다.그러나 비동기적이고 언제든지 발생하는 네트워크 이벤트에는 문제가 있습니다.대기열이 비어 있지 않고 네트워크 이벤트가 발생하면 대기열에 이미 있는 이벤트를 처리하기 전에 컴퓨터가 대기 상태에 있기 때문에 대기열에 넣을 수 없습니다.그리고 이 네트워크 이벤트는 이전에 대기열에 배치된 모든 이벤트 뒤에서 기다리고 있기 때문에 머신은 영원히 기다릴 것입니다.
이 문제를 극복하기 위해 두 가지 유형의 메시지가 있습니다.일반 및 우선 순위.일반 것은 내가 보낸 것이고 우선 순위는 모두 네트워크입니다.네트워크 이벤트를 받으면 대기열에 넣지 않고 컴퓨터로 직접 보냅니다.이렇게 하면 이벤트 대기열에서 다음 이벤트를 가져오기 전에 현재 작업을 완료하고 다음 상태로 진행할 수 있습니다.
내 이벤트와 네트워크 이벤트가 정확히 1:1 인터리브되어 있기 때문에 이러한 방식으로 설계되었습니다.이로 인해 기계가 네트워크 이벤트를 기다리고 있을 때 아무것도 하지 않고(그래서 이를 수락할 준비가 되어 있고 놓치지 않습니다) 그 반대도 마찬가지입니다. 기계가 내 작업을 기다릴 때 다른 작업이 아닌 내 작업만 기다리고 있습니다. 네트워크 하나.

지금보다 좀 더 심플한 디자인이 나왔으면 하는 마음에 이런 질문을 하게 되었습니다.

엄밀히 말하면 할 수 없습니다."연결 중" 상태만 있으므로 나중에 상위 로그인이 필요한지 여부를 알 수 없습니다.시작 상태에서 "연결 후 로그인" 이벤트의 결과를 나타내려면 "ConnectingWithIntentToLogin" 상태를 도입해야 합니다.

당연히 "Connecting" 상태와 "ConnectingWithIntentToLogin" 상태 사이에는 중복되는 부분이 많이 있을 것입니다.이는 상태 계층을 지원하는 상태 머신 아키텍처를 통해 가장 쉽게 달성됩니다.

--- 편집하다 ---

이후의 반응을 읽으면 이제 실제 문제가 무엇인지 분명해졌습니다.

FSM에 내장되어 있든, FSM 외부에 별도의 대기열이 있든 관계없이 추가 상태가 필요합니다.대기열에 추가 이벤트를 추가하여 선호하는 모델을 따르겠습니다.여기서 문제는 실시간 이벤트와 비교하여 대기 중인 이벤트를 "인터리브"하는 방법이 궁금하다는 것입니다.그렇지 않습니다. 특정 상태에 들어갈 때 대기열의 이벤트가 적극적으로 추출됩니다.귀하의 경우에는 "연결됨"과 같은 "*ed" 상태가 됩니다.대기열이 비어 있는 경우에만 "연결됨" 상태를 유지합니다.

차단하고 싶지 않다면 네트워크 응답에 신경 쓰지 않는다는 의미입니다.반면에 답변에 관심이 있다면 해당 답변을 기다리는 것을 차단해야 합니다.FSM을 다르게 설계하려고 하면 자동 장치의 크기가 빠르게 무한대에 도달하게 됩니다.

상태 머신을 다른 스레드로 이동하는 것은 어떻습니까?이자형.Q스레드.상태 머신에 입력 큐를 삽입하여 비차단 쿼리를 보낼 수 있고 출력 큐를 사용하여 쿼리 결과를 읽을 수 있습니다.쿼리 결과가 도착하면 connect(...)를 통해 메인 스레드에서 슬롯 함수를 콜백할 수도 있습니다. Qt는 이 점에서 스레드로부터 안전합니다.

이렇게 하면 주 프로그램을 차단하지 않고도 상태 머신이 필요한 만큼 차단할 수 있습니다.

백그라운드에서 차단 I/O 목록을 작성하려는 것 같습니다.

따라서 스레드를 실행하십시오.

while( !commands.empty() )
{
  command = command.pop_back();
  switch( command )
  {
  Connect: 
    DoBlockingConnect();
    break;
  ...
  }
}
NotifySenderDone();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top