Pergunta

Desculpe se eu estou pedindo a mesma pergunta novamente, mas quer verificar!

Eu tenho dois processos P1 e P2.

P1 é um escritor (Produtor).
P2 é um leitor (Consumidor).

Há alguma memória compartilhada ou um arquivo que P1 escreve e logo que P1 escreve, P2 deve ser notificado para a leitura.

Agora, como por meu pseudocódigo compreensão de P1 deve ser

Open shared file
Create a named event("Writedone") to signal write for P2 process
Do some processing on file
Mutex.Lock()
Write to File
Mutex.Unlock()
Signal named Event.
CloseHandle on file

Agora, em P2

Open handle to Shared file
Open handle to named event
WaitForSingleEvent on named event("Writedone")
Read from file
CloseHandle on file

Perguntas:

  1. É necessário ter bloqueios no leitor? O leitor vai apenas ler o arquivo e não mudá-lo. Então eu acho que há bloqueios são necessários no leitor. Pensamentos? ele pode dar errado em alguns casos, sem fechaduras?
  2. Estou abrindo e fechando os punhos para o arquivo de cada vez durante a leitura e escrita. Eu acho que não é necessário. Eu posso abrir o identificador de arquivo no construtor e fechá-lo no processo de destruição de leitor e escritor. Mas eu posso ler a partir do arquivo quando ele está sendo usado por escrito?

EDIT:. Toda vez que o escritor está escrevendo 10 bytes no final do arquivo e o leitor deve ler as últimas 10 bytes escritos pelo escritor

Foi útil?

Solução

A resposta é: não é necessário bloqueio se (e somente se) os dois segmentos podem utilizar os mesmos recursos compartilhados ao mesmo tempo. Não há informações suficientes sobre a sua implementação específica, mas eu tenho algumas observações:

  1. O bloqueio somente durante a escrita não faz sentido. Ele só adiciona alguma sobrecarga, mas não impede a partir de qualquer acesso simultâneo até que o leitor também está bloqueado corretamente.
  2. Locking seria necessário se as operações de arquivo que modificam as estruturas relacionadas com descritores do arquivo não são sincronizados de forma alguma. Pode acontecer que P1 poderia começar a escrever para o arquivo quando P2 ainda está lendo. Se leitura e escrita operações modificar as mesmas estruturas do sistema sem qualquer sincronização subjacente que você vai acabar com dados corrompidos. É difícil dizer se este é o caso aqui, porque você não mencionou que (bibliotecas) função particular que você usou. operações de arquivo são sincronizadas na maioria dos sistemas, por isso não deve ser um problema.
  3. A partir do que você escreveu sobre "10 bytes porções de informação", o bloqueio explícito parece não ser necessário (a menos que # 2 não impô-lo). P1 produz quantum de dados. Quando os dados estão prontos para serem lidos notifica P1 P2 sobre isso (pelo evento; passagem evento devem ser sincronizados internamente, de qualquer forma). P2 sabe que podia ler quantum de dados e, em seguida, precisa esperar para notificação posterior. Pode acontecer que a notificação posterior seria enviado antes anterior é tratado. Assim, os eventos precisa ser na fila de alguma forma. Você também pode usar semáforo em vez de notificação de eventos.

Outras dicas

Você precisa o leitor a obter um bloqueio - o uso de eventos não é nenhum substituto. Sem ele, um escritor poderia começar a escrever em qualquer ponto no código leitor.

É absolutamente necessário o consumidor a fechadura, a fim de evitar que o Produtor de acrescentar ao arquivo antes de o leitor pode ler. Imagine este cenário:

Producer writes and signals
Consumer receives signal
Consumer opens the file
Producer fires again and writes another 10 bytes
Producer signals
Consumer reads the last 10 bytes
Consumer closes the file

O que acontece a seguir depende se o seu evento nomeado é reset manual ou auto-reset. Se é auto-reset, então o consumidor vai ver o segundo sinal, e voltar e ler a mesma coisa novamente. Se for reset manual, então o consumidor vai redefinir o evento e perder a última coisa que o produtor escreveu.

Note que, mesmo com o bloqueio você tem uma condição de corrida se o produtor pode responder com rapidez suficiente. Ou seja, o produtor pode ser capaz de colocar um segundo registro no arquivo antes de o consumidor é capaz de ler o primeiro.

Parece que o que você tem aqui é uma fila FIFO implementado em um arquivo, e você está dependendo da capacidade do consumidor para processar dados mais rapidamente do que o produtor pode criá-lo. Se você pode garantia que o comportamento, então você está bem. Caso contrário, o consumidor terá de manter o controle de onde ele última leitura para que ele saiba onde ele deve ler em seguida.

  1. Você precisa fazer para travar o mutex no leitor, se o escritor pode começar a escrever a qualquer momento. Verifique se o mutex é um nomeado um modo P2 pode abri-lo.

  2. Se você abrir o arquivo com FileShare.ReadWrite em ambos os processos, você pode deixá-la aberta.

No leitor, você pode ter que procurar para o lugar que você bateu EOF antes de você pode ler novamente.

Se você tem certeza que o escritor está sempre adicionando e você pode dizer onde um termina de registro (porque eles são sempre 10 bytes por exemplo), e você pode aceitar um pequeno atraso, eo escritor escreve sempre registros completos, você pode fazer isso sem semáforos e eventos de todo. Abra o arquivo com FileShare.ReadWrite, e no leitor, continuar buscando ao mesmo lugar e tentar ler o seu registro, e dormir por um segundo, se você não podia. Se você conseguir ler um registro inteiro, você tem um. Descobrir a sua posição e loop de volta para buscar a esse lugar e tentar ler novamente. Este é tipo de como funciona a cauda -f em Unix.

Além de funções de sincronização normais, você pode usar o API de notificação de alteração de arquivo no Windows para esperar por alterações de arquivos.

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