Em sistemas Unix, por que precisamos explicitamente dos arquivos 'open' e 'close' para 'read' ou 'write' deles?

51

Por que open() e close() existem no design do sistema de arquivos Unix?

O sistema operacional não pôde detectar a primeira vez em que read() ou write() foi chamado e fez o que o open() normalmente faria?

    
por user5977637 25.02.2016 / 02:47

8 respostas

61

Dennis Ritchie menciona em «A Evolução do Sistema Unix de Compartilhamento de Tempo» que open e close , juntamente com read , write e creat estavam presentes no sistema desde o início.

Eu acho que um sistema sem open e close não seria inconcebível, mas acredito que isso complicaria o design. Você geralmente deseja fazer várias chamadas de leitura e gravação, não apenas uma, e isso provavelmente é verdade especialmente naqueles computadores antigos com RAM muito limitada na qual o UNIX se originou. Ter um identificador que mantenha a posição atual do arquivo simplifica isso. Se read ou write retornassem o identificador, eles teriam que retornar um par - um identificador e seu próprio status de retorno. A parte do identificador do par seria inútil para todas as outras chamadas, o que tornaria esse arranjo estranho. Deixar o estado do cursor no kernel permite melhorar a eficiência não apenas pelo buffering. Há também algum custo associado à pesquisa de caminho - ter uma alça permite que você pague apenas uma vez. Além disso, alguns arquivos na visão de mundo do UNIX não têm sequer um caminho de sistema de arquivos (ou não - agora eles fazem com coisas como /proc/self/fd ).

    
por 25.02.2016 / 03:18
53

Então, todas as chamadas read e write teriam que passar essas informações em cada operação:

  • o nome do arquivo
  • as permissões do arquivo
  • se o chamador está anexando ou criando
  • se o chamador está pronto trabalhando com o arquivo (para descartar buffers de leitura não utilizados e garantir que os buffers de gravação realmente terminem de escrever)

Se você considera as chamadas independentes open , read , write e close como sendo mais simples do que uma mensagem de E / S de fim único baseia-se na sua filosofia de design. Os desenvolvedores do Unix escolheram usar operações e programas simples que podem ser combinados de várias maneiras, em vez de uma única operação (ou programa) que faz tudo.

    
por 25.02.2016 / 02:55
52

O conceito do identificador de arquivo é importante por causa da escolha de design do UNIX que "tudo é um arquivo", incluindo coisas que não fazem parte do sistema de arquivos. Tais como unidades de fita, o teclado e tela (ou teletipo!), Cartões perfurados / leitores de fita, conexões seriais, conexões de rede e (a chave da invenção do UNIX) conexões diretas para outros programas chamados "tubos".

Se você observar muitos dos utilitários UNIX padrão simples, como grep , especialmente em suas versões originais, perceberá que eles não incluem chamadas para open() e close() , mas apenas read e %código%. Os manipuladores de arquivos são configurados fora do programa pelo shell e passados quando ele é iniciado. Portanto, o programa não precisa se preocupar em escrever para um arquivo ou para outro programa.

Além de write , as outras formas de obter descritores de arquivos são open , socket , listen , pipe e um mecanismo muito Heath Robinson para enviar descritores de arquivos em pipes: link

Editar: algumas anotações da palestra descrevendo as camadas de indireção e como isso permite que O_APPEND funcione de maneira sensata. Observe que manter os dados do inode na memória garante que o sistema não precisará ir buscá-los novamente para a próxima operação de gravação.

    
por 25.02.2016 / 11:02
10

A resposta é não, porque open () e close () criam e destroem um handle, respectivamente. Há momentos (bem, todo o tempo, realmente) em que você pode querer garantir que você é o único chamador com um nível de acesso específico, pois outro chamador (por exemplo) que escreve em um arquivo que você está analisando inesperadamente pode deixar um aplicativo em um estado desconhecido ou levar a um livelock ou deadlock, por exemplo o lema dos filósofos jantando.

Mesmo sem essa consideração, há implicações de desempenho a serem consideradas; close () permite que o sistema de arquivos (se for apropriado ou se você ligou para ele) liberar o buffer que você estava ocupando, uma operação cara. Várias edições consecutivas em um fluxo na memória são muito mais eficientes do que vários ciclos de leitura-gravação-modificação essencialmente não relacionados a um sistema de arquivos que, pelo que sabemos, existe a meio mundo de distância de um datacenter de armazenamento em massa de alta latência. Mesmo com o armazenamento local, a memória é normalmente muito mais rápida que o armazenamento a granel.

    
por 25.02.2016 / 07:54
7

O Open () oferece uma maneira de bloquear arquivos enquanto eles estão em uso. Se os arquivos fossem abertos automaticamente, lidos / gravados e depois fechados novamente pelo sistema operacional, não haveria nada para impedir que outros aplicativos alterassem esses arquivos entre as operações.

Embora isso possa ser gerenciável (muitos sistemas suportam acesso a arquivos não exclusivos) para simplificar, a maioria dos aplicativos pressupõe que os arquivos que eles abrem não mudam.

    
por 25.02.2016 / 12:32
5

Porque o caminho do arquivo pode se mover enquanto você espera que ele permaneça o mesmo.

    
por 26.02.2016 / 19:59
4

Ler e gravar em um sistema de arquivos may envolve uma grande variedade de esquemas de armazenamento em buffer, manutenção do sistema operacional, gerenciamento de disco de baixo nível e uma série de outras ações em potencial. Assim, as ações de open() e close() servem como preparação para esses tipos de atividades. Diferentes implementações de um sistema de arquivos podem ser altamente personalizadas conforme necessário e ainda permanecerem transparentes para o programa de chamada.

Se o SO não tivesse aberto / fechado, então com read ou write , essas ações de arquivo ainda teriam que executar quaisquer inicializações, liberação / gerenciamento de buffer, etc cada vez. Isso é muita sobrecarga para impor leituras e gravações repetitivas.

    
por 25.02.2016 / 17:16
1

O mantra Unix é "oferecer uma maneira de fazer as coisas", o que significa "fatoração" em peças (reutilizáveis) a serem combinadas à vontade. Ou seja, neste caso, separe a criação e a destruição de identificadores de arquivo de seu uso. Benefícios importantes vieram depois, com pipes e conexões de rede (eles também são manipulados por meio de identificadores de arquivos, mas são criados de outras maneiras). O envio de identificadores de arquivos (por exemplo, passá-los para processos-filhos como "arquivos abertos" que sobrevivem a um exec(2) e até mesmo para processos não relacionados por meio de um canal) só é possível dessa maneira. Particularmente, se você quiser oferecer acesso controlado a um arquivo protegido. Então você pode, por exemplo abra /etc/passwd para escrever, e passe isso para um processo filho que não tem permissão para abrir esse arquivo para escrever (sim, eu sei que esse é um exemplo ridículo, sinta-se à vontade para editar com algo mais realista).

    
por 29.02.2016 / 13:20