Problema de simultaneidade para cancelamento de ciclo de pesquisa longa

9

Tenho um problema que espero resolver escrevendo esta pergunta, mas, se não, vou postar e ver se alguém pode ajudar.

Estou usando uma biblioteca cliente (que é mal escrita, sinto) para interagir com um servidor de bate-papo em tempo real que utiliza o estilo COMET de longa pesquisa sobre HTTP. Estou tendo problemas com o cancelamento da longa pesquisa em determinadas situações e suspeito que possa precisar adicionar algum código de manipulação de concorrência, mas estou achando difícil encontrar a melhor maneira de fazer isso pelas razões abaixo.

O código de inscrição (que insere a votação longa) é implementado como um grande loop com o seguinte

doLongPoll()
{
    while(true)
    }
        //IF channel field boolean unsubscribe == TRUE, if so BREAK;
        //perform GET request (and store channel HTTPClient used for this call)
        //remove HTTPClient used for this call
        //IF channel field boolean unsubscribe == true, if so BREAK;
        //IF connection problem sleep(1500) then CONTINUE
        //post received data to listeners
    }
}

A chamada de cancelamento de assinatura (que será chamada em outro thread)

unsubscribe()
{
    //set channel field boolean unsubscribe == FALSE
    //get channel HTTPClient and shutdown
}

Eu isolei o caso do problema em que as operações são intercaladas. Para mim, isso parece ser o resultado do código ser multi-threaded e o código do cliente não ser thread-safe. Também o mau gerenciamento e a não reutilização do httpClient não está ajudando.

Um dos problemas que estou tendo é abaixo de onde a chamada de cancelamento de inscrição não impede que o próximo getRequest ocorra.

THREAD 1 (polling)                      THREAD 2
--------                                --------
do unsubscribe check (pass)
                                        unsubscribe called
                                        set unsubscribe = true
                                        check if httpClient saved (none)
perform getRequest (save HttpClient first)

Eu gostaria de saber o que as pessoas acham que seria a melhor abordagem para esse problema (o tempo também é limitado, então não posso reescrever muito do código!)

Para corrigir isso, eu pensava que poderia usar um bloco de sincronização da primeira verificação de cancelamento de inscrição no thread 1 até o ponto em que httpClient fosse salvo antes que a solicitação get real fosse executada e syncronise o método de cancelamento de assinatura usando o mesmo bloqueio. Isso não é prático no momento, pois o primeiro bloco de sincronização mencionado começaria em uma chamada de método e terminaria mais abaixo na cadeia de chamadas do método (devido à forma como a biblioteca é escrita) - o que é muito errado, portanto seria necessária alguma refatoração. p>

OU Eu poderia criar apenas um único httpClient por canal em vez de por solicitação e, em seguida, sempre poderia ser desligado e eu poderia potencialmente ignorar a sincronização (eu acho).

OU, como sugerido abaixo, eu poderia usar interrupções para o mesmo propósito

Todas as sugestões serão bem-vindas - vou editar se tiver algum progresso!

Obrigado

    
por Dori 08.01.2013 в 13:11
fonte

2 respostas

3

Comprei Java Concurrency in Practice como resultado disso problema e descobriu que eles discutem um problema muito parecido com este em Capítulo 7: Cancelamento e desligamento , que pode ser resumido pela citação

  

A interrupção geralmente é a maneira mais bem-sucedida de implementar   cancelamento

Como o HttpClient está bloqueando o socket IO que não suporta interrupção, eu tenho uma abordagem em duas frentes. Eu aloco meu httpClient , eu verifico a interrupção imediatamente antes da chamada httpClient.execute() real e no meu método unsubscribe() interromper o segmento e, em seguida, chamar httpClient.getConnectionManager().shutdown(); . Isso parece cuidar do meu problema e foi uma mudança muito simples. Não há mais problemas de intercalação!

Eu também defino o campo booleano unsubscribe como volatile como sugerido, o que eu deveria ter feito antes - somente isso, no entanto, não teria resolvido o problema

    
por Dori 11.01.2013 / 11:23
fonte
2

1) Defina unsubscribe como volátil

2) Para maior segurança, proteja o acesso (leitura / gravação) para cancelar a assinatura com, por exemplo, um semáforo

    
por pringi 08.01.2013 / 14:40
fonte