Pergunta

Eu estou usando o framework Qt, que tem por padrão non-blocking I / O para desenvolver um aplicativo como navegar pelas várias páginas da web (lojas online) e realizar ações diferentes sobre estas páginas. Eu sou "mapeamento" página específica da Web para uma máquina de estado que eu uso para navegar através desta página.
Esta máquina estado tem essas transições;
Connect, LogIn, Query, LogOut, Disconnect
e esses estados;
Start, Connecting, Connected, LoggingIn, LoggedIn, Querying, QueryDone, LoggingOut, LoggedOut, Disconnecting, Disconnected
Transições de * ing para os estados ed * (Connecting->Connected), são devido a LoadFinished eventos de rede assíncronos recebidos do objeto de rede, quando actualmente solicitado url é carregado. Transições de * ed para * ing estados (Connected->LoggingIn) são devido a eventos enviar por mim.
Eu quero ser capaz de enviar vários eventos (comandos) para esta máquina (como Connect, login, consulta ( "productA"), consulta ( "ProductB"), logout, login, consulta ( "productC"), logout, Disconnect) ao mesmo tempo e tê-lo processá-los. I não deseja bloquear aguardando a máquina para acabamento processamento de todos os eventos que enviei a ele. O problema é que eles têm que ser intercalados com os eventos de rede acima mencionados informando máquina sobre a url a ser transferidos. Sem intercalação máquina não pode avançar seu estado (e processar meus eventos), porque avançando de ing * a * ed ocorre apenas depois de receber o tipo de rede de evento.

Como posso conseguir meu objetivo design?

Editar

  1. A máquina de estado que estou usando tem seu próprio ciclo de eventos e acontecimentos não são enfileiradas em que isso pode ser perdida por máquina, se eles vêm quando a máquina está ocupado.
  2. eventos / s de rede não são lançados diretamente a nem a máquina de estado nem a fila de eventos que estou usando. Eles são enviados para o meu código (manipulador) e eu tenho que lidar com eles. Eu posso enviá-los como eu desejo, mas por favor tenha em mente observação não. 1.
  3. Dê uma olhada no meu resposta a esta pergunta onde eu descrevi meu projeto atual em detalhes. A questão é se e como posso melhorar este projeto, tornando-

    • Mais robusta
    • Mais simples
Foi útil?

Solução

Parece que você quer a máquina do Estado para ter uma fila de eventos. Fila até os eventos, iniciar o processamento da primeira, e quando que completa puxar o próximo evento fora da fila e começar com isso. Então, ao invés da máquina estatal sendo conduzido pelo código do cliente diretamente, ele é impulsionado pela fila.

Isto significa que qualquer lógica que envolve o uso do resultado de uma transição no próximo tem que ser na máquina. Por exemplo, se o "login completa" página diz-lhe para onde ir. Se isso não for possível, então o evento, talvez, poderia incluir uma chamada de retorno que a máquina pode chamar, para retornar tudo o que ele precisa saber.

Outras dicas

Esta pergunta eu já tinha um projeto de trabalho que eu não quero escrever sobre não respostas de inclinação em qualquer direção :) Eu vou descrever nesta resposta pseudo que o projeto que eu tenho é.

Além da máquina de estado eu tenho uma fila de eventos. Em vez de enviar eventos diretamente para a máquina que eu estou colocando-os na fila. Há, porém, problemas com eventos de rede que são assíncronas e vir em qualquer momento. Se a fila não está vazio e um evento de rede vem Eu não posso colocá-lo na fila porque a máquina estará esperando preso por ele antes de processar eventos já na fila. E a máquina vai esperar para sempre, porque este evento rede está esperando atrás de todos os eventos colocados na fila mais cedo.
Para ultrapassar este problema Eu tenho dois tipos de mensagens; normais e prioridade. os normais são aqueles Enviar por mim e aqueles prioritários são todos aqueles rede. Quando eu chegar em evento de rede que eu não colocá-lo na fila, mas em vez disso, enviá-lo diretamente para a máquina. Desta forma, ele pode concluir sua tarefa atual e avançar para o próximo estado antes de puxar o próximo evento da fila de eventos.
Ele funciona concebido desta forma só porque há exatamente 1: 1 interleave dos meus eventos e eventos de rede. Devido a isso, quando a máquina está à espera de um evento de rede que não está ocupado fazendo nada (que ele está pronto para aceitá-lo e não perder) e vice-versa - quando a máquina aguarda a minha tarefa é só esperando a minha tarefa e não outro rede um.

Eu fiz esta pergunta na esperança de algum projeto mais simples do que o que eu tenho agora.

Estritamente falando, você não pode. Porque você só tem estado "Conexão", você não sabe se você precisa de topo de login depois. Você teria que apresentar um estado "ConnectingWithIntentToLogin" para representar o resultado de um "Connect, em seguida, Login" evento do estado inicial.

Naturalmente, haverá um monte de sobreposição entre os estados "ConnectingWithIntentToLogin" "Conexão" e. Isso é mais facilmente alcançado por uma arquitetura de máquina de estado que suporta hierarquias do Estado.

--- --- editar

Lendo suas reações posteriores, é agora claro o que o seu problema é real.

Você precisa estado extra, obviamente, se isso é enraizado no FSM ou fora dela em uma fila separada. Vamos seguir o modelo de sua preferência, com eventos extras em uma fila. O rick aqui é que você está querendo saber como "intercalação" esses eventos enfileirados vis-à-vis os eventos em tempo real. Você não - eventos da fila estão ativamente extraído quando entrar em estados específicos. No seu caso, esses seriam os estados "* ed" como "Conectado". Somente quando a fila está vazia que você iria ficar no estado "ligado".

Se você não deseja bloquear, isso significa que você não se preocupam com as respostas da rede. Se, por outro lado, o interesse que responde, você tem que bloquear esperando por eles. Tentando projetar seu FSM caso contrário vai levar rapidamente ao infinito atingindo o tamanho do seu autômato.

Como cerca de mover a máquina do Estado para um segmento diferente, i. e. QThread. Eu implent uma fila de entrada na máquina de estado para que eu pudesse enviar consultas não bloqueio e uma fila de saída para ler os resultados das consultas. Você pode até mesmo chamar de volta uma função de fenda em seu segmento principal via de ligação (...) se um resultado de uma consulta chega, Qt é o segmento de seguros nesse sentido.

Desta forma, sua máquina de estado poderia bloquear contanto que ele precisa sem bloquear o seu programa principal.

Parece que você só quer fazer uma lista de bloqueio de I / O no fundo.

Então, tem um fio de execução:

while( !commands.empty() )
{
  command = command.pop_back();
  switch( command )
  {
  Connect: 
    DoBlockingConnect();
    break;
  ...
  }
}
NotifySenderDone();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top