É possível alterar o IDENTIFICADOR que foi aberto para e/S síncrona para ser aberto para e/S assíncrona durante a sua vida útil?

StackOverflow https://stackoverflow.com/questions/2475713

Pergunta

A maioria dos meus programação diária de trabalho do Windows é hoje em torno de operações de e/S de todo o tipo (tubos, consoles, arquivos, sockets, ...).Eu estou bem ciente de diferentes métodos de leitura e escrita de/para diferentes tipos de alças (Síncrona, assíncrona de espera para realização de eventos, aguardando Identificadores de arquivo, e/S de portas de conclusão de e alertable e/S).Usamos muitos daqueles.

Para alguns de nossos aplicativos seria muito útil ter apenas uma maneira de tratar a todos os identificadores.Quero dizer, o programa pode não saber, que tipo de identificador que ele tenha recebido e que gostaríamos de usar, digamos, de conclusão de e/S de portas para todos.

Assim, em primeiro lugar, gostaria de perguntar:

Vamos supor que eu tenha um identificador de:

HANDLE h;

qual foi recebido pelo meu processo de I/O de algum lugar.Existe alguma forma fácil e fiável para encontrar para fora o que sinalizadores de ter sido criada?A principal bandeira em questão é FILE_FLAG_OVERLAPPED.

A única maneira conhecida para mim até agora, é para tentar registrar como alavanca para a conclusão de e/S de porta (usando CreateIoCompletionPort()).Se tiver êxito a alça foi criado com FILE_FLAG_OVERLAPPED.Mas, em seguida, apenas a conclusão de e/S de porta deve ser utilizado, como o identificador não pode ser registados a partir-lo sem fechar a HANDLE h em si.

Desde que exista uma fácil maneira para determinar a presença de FILE_FLAG_OVERLAPPED, que chegaria a minha segunda pergunta:

Existe alguma forma de como adicionar bandeira como a já existente lidar?Que gostaria de fazer um identificador que foi originalmente aberto para operações síncronas de ser assíncrona.Haveria uma maneira de como criar oposto (remover o FILE_FLAG_OVERLAPPED para criar síncrona identificador de assíncrono)?

Eu não encontrei qualquer forma direta após a leitura através da MSDN e pesquisando muito.Haveria, pelo menos, algum truque que poderia fazer o mesmo?Como re-criar a alça no mesmo caminho usando CreateFile() função ou algo semelhante?Algo ainda parcialmente documentados ou não documentadas em tudo?

O principal lugar onde eu precisaria deste, é determinar o caminho (ou alterar a forma) processo de leitura/gravação de alças enviadas por aplicativos de terceiros.Nós não podemos controlar como os produtos de terceiros criar suas alças.

Querido Windows gurus:ajuda por favor!

No que respeita

Martin

Foi útil?

Solução 2

3 anos se passaram e o Windows 8 foi lançado.Graças a regressão apresentada na implementação do console no Windows 8 eu tenho que fazer algo sobre o problema que desencadeou esta questão.Então, eu finalmente tentou usar ReOpenFile() chamada de função.

Em uma frase:para os meus propósitos, é inútil.

O ReOpenFile() API é utilizada para "tomar um identificador de arquivo existente e a obtenção de outro identificador que tem um diferente conjunto de direitos de acesso".Pelo menos é o indicado no artigo original.

Eu tentei usar O ReOpenFile() na entrada do Console identificador:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

E o que eu recebo é:erro 1168:"Elemento Não Encontrado"."Obrigado Microsoft".Eu não vou nem tentar usá-lo para pipes anônimos, desde que a documentação estados:

"Assíncrona (sobreposto) operações de leitura e escrita não são suportados por anônimo tubos.Isso significa que você não pode usar o ReadFileEx e WriteFileEx funções com pipes anônimos.Além disso, o parâmetro lpOverlapped de ReadFile e WriteFile é ignorado quando essas funções são usadas com pipes anônimos."

Obrigado, povo, tudo para o seu sugestões.Durante a leitura de lidar de forma assíncrona, a pessoa tem que estar pronto também para o fato de que a operação pode ser concluída de forma síncrona.Que eu saiba.A principal razão de eu estar fazendo essa pergunta é:

quando uma leitura síncrona foi emitida em alguns objetos (pelo menos anônimo tubos, e a entrada do console no Windows 8), em seguida, chamar CloseHandle() a partir de outro thread no mesmo identificador vai falhar ou deixar de responder, até o ReadFile() concluído;isso significa que ele irá deixar de responder indefinidamente em muitos casos.Essa é a razão pela qual eu queria substituir o síncrona lidar com assíncrona.

Agora está claro para mim, que simplesmente não é possível em sistemas operacionais Windows para cancelar algumas operações de leitura em forma direta.Quando a leitura síncrona alças, um só tem de sair do aplicativo, mesmo se ReadFile() ainda é a leitura a partir de um identificador na linha, porque isso é simplesmente impossível confiável de despertar tal uma operação de leitura.Em saber...No mais recente sistema operacional é possível cancelar a operação.No entanto, não há nenhuma maneira de saber o tempo que o thread está em ReadFile() ligue já, ou ainda não.Se ReadFile() não é chamado ainda, então não existe operação para cancelar e subseqüentes de leitura irá travar.A única forma seria a de fechar o punho, mas que a operação deixa de responder ou falha em alguns objetos e em alguns sistemas operacionais.A única solução adequada para isso é a e/S assíncrona.Mas, como mencionei no início, nosso APLICATIVO é iniciado por aplicações de terceiros, e não podemos forçá-los a todos a sempre criar pipes nomeados com sobreposto sinalizador definido para o stdio.

Eu sou de desistir e ir para implementar desagradável de truques feios...vamos ter que continuar lendo sem estrutura SOBREPOSTA de Alças que tenham sido criados com SOBREPOSTO bandeira, e vazamento de alças e threads....

Outras dicas

Vejo que eu era um mau leitor de msdn:/ eu perdi totalmente a função ReOpenFile() que foi introduzido provavelmente em junho de 2003 no Windows Server 2003 (de acordo com Este artigo). Para me defender pelo menos um pouco: eu esperaria o CreateFile() descrição para referência cruzada para ReOpenFile() Descrição. Há uma referência em ReOpenFile() página para CreateFile() página, mas não o contrário.

Esta função parece permitir exatamente o que eu preciso: adicionar ou remover FILE_FLAG_OVELRAPPED Para/a partir de alças já existentes, criando uma nova alça com as propriedades desejadas! : -Di ainda não o testou. Infelizmente, está disponível apenas no Windows 2003 Server, Windows Vista e em diante. Pergunta sobre as versões anteriores do SO foi respondida aqui. A função não existe na API pública no sistema operacional antes do servidor Windows 2003. É usado pela implementação subjacente, mas não está disponível para desenvolvedores nesses sistemas (não suportados).

Isso praticamente significa que não há esperança para mim pelo menos nos próximos anos, até que soltemos suporte para plataformas mais antigas do Windows. Isso também significa que a situação em relação à E/S tem sido muito ruim no SO mais antigo que o Windows Vista. Outra parte dolorosa que está ausente foi a possibilidade de cancelar a E/S síncrona e assíncrona nesses sistemas mais antigos.

Além disso, ainda sinto falta de uma parte da resposta: a presença de bandeiras pode ser testada por algum meio? Eu não encontrei função para fazer isso. Isso significa que, se queremos garantir a presença de algum sinalizador no objeto de arquivo, o arquivo sempre deve ser reaberto.

Se eu entender o que você procura, gostaria de sugerir que você não se importe se fosse aberto com a bandeira sobreposta ou não. Eu acredito que você pode passar com segurança em um OVERLAPPED estrutura nos casos síncronos e assíncronos. Seu código precisa ser capaz de lidar ReadFile() retornando false e GetLastError() retornando ERROR_IO_PENDING. Você também precisará adicionar chamadas apropriadas a GetOverlappedResult(), WaitForSingleObject(), etc.

O artigo do MSDN sobre ReadFile() Tem algumas boas informações sobre isso em "Considerações para trabalhar com alças de arquivo síncrono" e "considerações para trabalhar com alças de arquivo assíncronas" na seção "Sincronização e posição do arquivo".

Os sinalizadores de manipulação de teste provavelmente devem ser feitos da mesma maneira que testar as permissões com as quais a alça foi criada. Tente. Se a API falhar, tente o fallback. Se isso falhar, retorne um erro.

Eu acho que a coisa realmente reveladora é a maneira como a documentação do ReadFile diz: "Se o hfile for aberto com file_flag_overlapped, ... a função pode relatar incorretamente que a operação de leitura está concluída".

Minha interpretação do erro é (e a pergunta que você precisa fazer é): se fosse possível verificar o status sobreposto de um identificador de arquivo, por que o arquivo de leitura não faria essa verificação e, em seguida, validar a estrutura sobreposta de acordo, para explicitamente Falha se chamado de maneira não sobreposta com uma alça sobreposta?

Não sei uma maneira de determinar a bandeira de uma alça e os efeitos colaterais do uso da API Reabre, mas como seu objetivo era

Seria muito útil ter apenas uma maneira de tratar todas as alças

Se você deseja comportamento síncrono (Quero dizer, usando a API síncrona para alças não sobrepostas e API assíncrona alimentada com estrutura sobreposta com subsequente espera no evento do sobreposição) Você sempre pode usar a API assíncrona também se a alça foi aberta em modo não sobreposto Como já foi declarado por @brett
Posso confirmar que isso funciona (pelo menos para tubos nomeados) ES:

void connectSynchronous(HANDLE hPipeThatWeDontKnowItsFlag){
    ...
    BOOL bRet = ::ConnectNamedPipe(hPipeThatWeDontKnowItsFlag, pOverlapped);

    if(bRet == FALSE){
        DWORD dwLastErr = ::GetLastError();

        if(dwLastErr == ERROR_IO_PENDING){
            //The handle was opened for asynchronous IO so we have to wait for the operation
            ...waitFor on the overlapped hEvent;

        }else if(dwLastErr == ERROR_PIPE_CONNECTED){
            //The handle was opened for synchronous IO and the client was already connected before this call: that's OK!
            return;
        }else{
            throw Error(dwLastErr);
        }
    }/*else{
        //The handle was opened for synchronous IO and the client has connected: all OK
    }*/
}

Uma alternativa ao hack do CreateiociclortiontionPort é fazer um arquivo de leitura de byte zero com um lpoverado nulo. Se falhar com error_invalid_parameter, assuma que foi aberto com file_flag_overlapped.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top