Um processo é uma instância de um programa. Um programa pode ser instanciado várias vezes, isto é, vários processos podem ser criados com o mesmo código executável carregado. Eu gostaria de citar uma linha de Entendendo o Kernel do Linux por Daniel P. Bovet e Marco Cesati:
It is important to distinguish programs from processes; several processes can execute the same program concurrently, while the same process can execute several programs sequentially.
Basicamente, isso significa que, enquanto um programa pode ser executado em várias instâncias, uma única instância só pode carregar um código executável de cada vez. Assim, a partir daí, poderíamos dizer que nothing impede que um programa seja executado em várias instâncias, porque não há absolutamente nenhuma razão para proibi-lo. Naturalmente, esses processos não compartilharão nada além do 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 parece importante para mim quando se trata de sistemas do tipo Unix (mesmo livro):
Unix-like operating systems adopt a process/kernel model. Each process has the illusion that it’s the only process on the machine, and it has exclusive access to the operating system services.
Na verdade, é por isso que os sistemas Unix são multiprocessamento / multiprogramação, ou pelo menos, é a política sobre a qual esse recurso é baseado. Assim, devido a esse fato, não há como um processo saber de forma nativa que outro processo, executando exatamente o mesmo código, está aguardando ou trabalhando em outra CPU.
No entanto, cada processo sabe uma coisa: o sistema está sendo executado pelo kernel, e os serviços do kernel estão à disposição do processo o tempo todo que ele vai gastar trabalhando em uma CPU. Graças a isso, é possível que um processo consulte o kernel sobre outros processos em execução como instâncias do mesmo executável. A primeira solução que me vem à mente é ler o sistema de arquivos /proc
virtual. Este FS age como uma interface entre o usuário / aplicativo 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 desse diretório, você encontrará um link chamado exe
. Por exemplo, aqui está o meu diretório bash
process ', PID 22343:
lrwxrwxrwx /proc/22343/exe -> /bin/bash*
Agora, navegando pelo sistema de arquivos, você poderá encontrar processos que executam o mesmo código executável, ou seja, processos para os quais o link exe
tem como alvo o mesmo arquivo executável.
No entanto, como todos os sistemas Unix não implementam /proc
da mesma maneira, os desenvolvedores pretendem usar uma solução mais portátil, que depende de algo que praticamente todos os sistemas Unix entendem: arquivos comuns. É para isso que .pid
arquivos estão aqui.
Na maioria das vezes, você encontrará esses arquivos em /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 de se uma instância de um programa está sendo executada ou não. Normalmente, o conteúdo deste arquivo é feito simplesmente do PID do processo em execução. Nesse caso, tenho um processo acpid
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 pelo arquivo PID, programar um programa de instância única é muito 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
O uso de sinais no primeiro caso é o comportamento que eu mais tenho visto, no entanto, se seu aplicativo usa um IPC mais sofisticado (soquetes, filas de mensagens, ...), você pode usá-lo para informar que o usuário pediu algo que precisa fazer.