O que determina se um executável pode ser executado simultaneamente em diferentes processos independentes?

O que determina se um executável pode ser executado simultaneamente em diferentes processos independentes?

eu posteiuma perguntasobre como executar um executável (um visualizador de PDF) no wine de forma independente em vários processos (independente significa sem comunicação entre eles, não é computação paralela). Ouvi dizer que o editor de PDF (uma edição aprimorada do visualizador) de alguma empresa não pode fazer isso.

Questões

  • Então, eu me pergunto o que torna um arquivo executável capaz ou não de ser executado de forma independente em vários processos?
  • É implementado pelo próprio programa, por algumas bibliotecas?
  • O sistema operacional não pode fazer isso acontecer?

Responder1

É quase certo que isso é implementado pelo próprio programa e provavelmente impossível para o sistema operacional forçar todos, exceto os programas mais rudimentares.

Se, no entanto, você conhece a maneira pela qual o programa decide que já está em execução, e essa maneira é algo que você pode influenciar, então você pode de fato obter um executável para iniciar um novo processo (ou não).

Alguns aplicativos tornam isso particularmente fácil, como o Emacs. A maneira padrão de executar o Emacs é lançar um novo processo para cada invocação. Mas você também pode executar explicitamente o Emacs no modo servidor e depois executar emacsclientexplicitamente para informar ao servidor existente para visitar um novo arquivo.

Como exemplo oposto, o Firefox oferece uma opção de linha de comando -no-remoteque força o lançamento de um novo processo, enquanto o padrão é interagir com um processo já em execução, se possível.

Muitos aplicativos simples desenvolvidos internamente verificarão se outra versão dele já está em execução simplesmente consultando ps. Isso pode ser contornado de diversas maneiras. O problema com o software industrial é que o usuário quase nunca sabe como um determinado aplicativo decide se já está ou não em uso. Mesmo no Unix, onde você pode inspecionar todos os arquivos abertos com os quais um executável está interagindo, não há garantia de que você possa descobrir qual deles (se houver) é responsável por registrar o fato de que o aplicativo está em execução.

Responder2

Um processo é uma instância de um programa. Um programa pode ser instanciado diversas vezes, ou seja, vários processos podem ser criados com o mesmo código executável carregado.Gostaria de citar uma frase deCompreendendo o kernel do Linuxpor Daniel P. Bovet e Marco Cesati:

É importante distinguir programas de processos; vários processos podem executar o mesmo programasimultaneamente, enquanto o mesmo processo pode executar vários programassequencialmente.

Basicamente, isso significa que embora um programa possa sercorrerem vários casos, uma única instância só pode carregar um código executável por vez. Então, partindo daí, poderíamos dizer quenadaimpede que um programa seja executado em múltiplas instâncias, porque não há absolutamente nenhuma razão para proibi-lo. É claro que esses processos não compartilharão nada além de seu código de execução. Páginas de memória, descritores de arquivos (que podem dizer respeito a arquivos idênticos), e assim por diante... são completamente independentes de um processo para outro.

Outro ponto me parece importante quando se trata de sistemas do tipo Unix (mesmo livro):

Sistemas operacionais do tipo Unix adotamum modelo de processo/kernel.Cada processo tem a ilusão de que é o único processo na máquina, e tem acesso exclusivo aos serviços do sistema operacional.

Na verdade, é por isso que os sistemas Unix são multiprocessados/multiprogramados ou, pelo menos, é a política na qual esse recurso se baseia. Então, por esse mesmo fato, não há como um processosabe nativamenteque outro processo, executando exatamente o mesmo código, está aguardando ou trabalhando em outra CPU.

Porém, cada processo sabe uma coisa: o sistema está sendo executado pelo kernel, e os serviços do kernel estão à disposição do processo durante todo o tempo que ele gastará trabalhando em uma CPU. Graças a isso, é possível que um processoconsultao kernel sobre outros processos em execução como instâncias do mesmo executável. A primeira solução que me vem à mente é ler o /procsistema de arquivos virtual. Este FS atua como uma interface entre o usuário/aplicação e o kernel (já que esses arquivos representam estruturas e dados do kernel). Neste sistema de arquivos, cada processo recebe um diretório (nomeado com seu PID), e dentro deste diretório você encontrará um link chamado exe. Por exemplo, aqui está basho diretório do meu processo, PID 22343:

lrwxrwxrwx /proc/22343/exe -> /bin/bash*

Agora, navegando no sistema de arquivos, você poderá encontrar processos que executam o mesmo código executável, ou seja, processos para os quais o exelink tem como alvo o mesmo arquivo executável.

No entanto, como todos os sistemas Unix não são implementados /procda mesma maneira, os desenvolvedores pretendem usar uma solução mais portátil, que se baseia em algo que praticamente todos os sistemas Unix entendem: arquivos regulares. É para isso que .pidos arquivos geralmente servem.

Na maioria das vezes, você encontrará esses arquivos no formato /run. Por exemplo:

-rw-r--r-- /run/acpid.pid
-rw-r--r-- /run/atd.pid
-rw-r--r-- /run/crond.pid

Esses arquivos são criados pelo aplicativo ao qual pertencem e usados ​​como marcadores para indicar se uma instância de um programa está ou não em execução. Normalmente, o conteúdo deste arquivo é simplesmente composto pelo PID do processo em execução. Neste caso, tenho um acpidprocesso em execução, com PID 1503, e é exatamente isso que está no arquivo PID.

Agora, como todos os processos do mesmo programa compartilham o mesmo código de execução, eles compartilham suas constantes (pelo menos, seus valores). Por esse motivo, se cada instância souber onde procurar o arquivo PID, programar um programa de instância única é bastante fácil:

if (the pid file exists) then
    send a signal to the running process or just bring it on the foreground
    exit since the work is going to be handled by the already-running process
else
    actually start the program, the first instance
endif

Usar sinais no primeiro caso é o comportamento que mais tenho visto, porém, se sua aplicação utiliza algum IPC mais sofisticado (soquetes, filas de mensagens, ...), você poderia utilizá-lo para informá-la que o usuário solicitou algo que isso precisa ser feito.

informação relacionada