Definição:
...

  • Partilha da máquina física por programas independentes ou interdependentes.
  • Um processo é um programa executado pelo sistema operativo, realizando atividades diversas (editores, compiladores, comunicação).
  • Processos compartilham recursos físicos do computador e são executados em paralelo.

Estados de Funcionamento de um Processo:
...

Figura 3.2.png

  • Inicialização: Processo criado, espera recursos.
  • Pronto: Aguarda atribuição do processador.
  • Execução: Em posse da máquina física.
  • Espera: Aguarda evento ou comunicação.
  • Terminado: Execução concluída, deve notificar o processo pai.

Processo em Java:
...

Em Java, cria-se um processo com a classe ProcessBuilder, usando o nome do processo como parâmetro de entrada (nomeProcesso como String).
O processo é iniciado com o método start() da classe ProcessBuilder.

ProcessBuilder pb = new ProcessBuilder(nomeProcesso);
Process p = pb.start();

Exemplo "lancarEEsperarProcessoWin32"
...

Um exemplo completo de uma classe Java chamada "lancarEEsperarProcessoWin32" para lançar processos está descrito na figura 3.1.1.1.

public class lancarEsperarProcessoWin32 {
    ProcessBuilder pb; // Instância de ProcessBuilder para construir e iniciar processos
    Process p; // Instância de Process para representar o processo em execução

    // Método para lançar um processo Win32 com base no nome do executável (String s)
    public void lancarProcessoWin32(String s) {
        pb = new ProcessBuilder(s); // Cria um ProcessBuilder com o nome do processo
        try {
            p = pb.start(); // Inicia o processo
            System.out.println("Processo executando."); // Exibe mensagem de sucesso
        } catch (IOException e) {
            p = null; // Em caso de erro, define 'p' como nulo (sem processo em execução)
        }
    }

    // Método para esperar o término do processo lançado
    public void esperarFimProcessoWin32() {
        if (p != null) { // Verifica se há um processo em execução
            try {
                p.waitFor(); // Aguarda até que o processo termine
                System.out.println("Processo terminou."); // Exibe mensagem de término
            } catch (InterruptedException e) {
                p = null; // Em caso de interrupção, define 'p' como nulo
            }
        }
    }

    // Método principal (entry point) para testar a classe
    public static void main(String[] args) {
        lancarEsperarProcessoWin32 lep = new lancarEsperarProcessoWin32(); // Cria uma instância da classe
        lep.lancarProcessoWin32("c:\\Windows\\system32\\mspaint.exe"); // Lança o processo do MS Paint
        lep.esperarFimProcessoWin32(); // Espera o término do processo do MS Paint
    }
}

Detalhes:
...

  • É definida uma classe chamada lancarEsperarProcessoWin32.
  • O construtor da classe inicializa duas variáveis de instância: pb para ProcessBuilder e p para Process.
  • lancarProcessoWin32 é um método que lança um processo com base no nome do executável fornecido como argumento. Ele cria um novo ProcessBuilder, inicia o processo e exibe uma mensagem se a operação for bem-sucedida.
  • esperarFimProcessoWin32 é um método que espera que o processo em execução termine e exibe uma mensagem quando isso ocorre.
  • O método main é o ponto de entrada do programa e é usado para testar a classe. Ele cria uma instância de lancarEsperarProcessoWin32, lança o processo do MS Paint e espera que ele termine.

Executando um Programa Java como .JAR:
...

  • Um programa Java pode ser executado a partir do sistema operativo quando convertido em um arquivo executável .JAR.
  • Isso requer um programa Java com um método main() que serve como ponto de entrada.
  • No Eclipse, você pode criar um arquivo .JAR executável com os seguintes passos:
    1. Selecionar File -> Export -> Runnable JAR file.
    2. Clicar em NEXT.
    3. Definir a configuração de inicialização e o nome do arquivo .JAR.
    4. Clicar em Finish.

Exemplo "lancarEEsperarProcessoJAVA"
...

  • A classe Java completa chamada "lancarEEsperarProcessoJAVA" que executa um ou mais processos
public class lancarEEsperarProcessoJAVA {
    public static void main(String[] args) {
        // Forma de executar a partir de Java um processo Java
        Process p = null; // Declaração de uma variável de processo
        
        try {
            // Executa um processo Java a partir do comando "java -jar" com o arquivo T1.jar
            p = Runtime.getRuntime().exec("java -jar C:\\Users\\jpais\\Desktop\\T1.jar");
            System.out.println("T1 executando."); // Exibe que o processo T1 está em execução
        } catch (IOException e) {
            e.printStackTrace(); // Em caso de erro, imprime a exceção
        }
        
        if (p != null) { // Verifica se o processo foi lançado com sucesso
            try {
                // Espera pelo término do processo T1
                p.waitFor();
                System.out.println("T1 terminou."); // Exibe que o processo T1 terminou
            } catch (InterruptedException e) {
                System.err.println(e.getMessage()); // Em caso de interrupção, imprime a mensagem de erro
            }
        }
    }
}

Detalhes:
...

  • É criada uma variável p do tipo Process para representar o processo a ser lançado.
  • Dentro do bloco try, é utilizado Runtime.getRuntime().exec() para executar um processo Java com o comando "java -jar" e o arquivo T1.jar.
  • Se a execução for bem-sucedida, é exibida uma mensagem indicando que o processo T1 está em execução.
  • Em caso de erro (exceção IOException), é impresso o rastreamento da exceção.
  • Após isso, verifica-se se o processo foi lançado com sucesso (p não é nulo).
  • Dentro do segundo bloco try, p.waitFor() é usado para aguardar o término do processo T1.
  • Se a espera for interrompida (exceção InterruptedException), a mensagem de erro é impressa.

Comunicação entre Processos em Java
...

Em Java, a comunicação entre processos independentes (IPC - Inter-Process Communication) na mesma máquina pode ser realizada com as seguintes tecnologias:

- Memória partilhada.
- Sockets via TCP (Transfer Control Protocol).
- Sockets via UDP (User Datagram Protocol).

Para a comunicação entre máquinas diferentes, as tecnologias utilizadas incluem:

- Sockets via TCP (Transfer Control Protocol).
- Sockets via UDP (User Datagram Protocol).

O tempo necessário para a passagem de informações entre processos pode variar, e os tempos aproximados para cada técnica são:

- Memória partilhada com 1 núcleo de CPU: 1,5 microssegundos.
- Memória partilhada com mais de 1 núcleo de CPU: 0,7 microssegundos.
- TCP com 1 núcleo de CPU: 30 microssegundos.
- TCP com mais de 1 núcleo de CPU: 22 microssegundos.
- UDP com 1 núcleo de CPU: 5 microssegundos.
- UDP com mais de 1 núcleo de CPU: 8 microssegundos.

Essas tecnologias permitem que os processos em Java se comuniquem de maneira eficiente, escolhendo a melhor opção com base nas necessidades específicas de desempenho e requisitos de comunicação.

Comunicação entre Processos com Memória Partilhada
...

Em Java, a comunicação entre processos independentes (IPC - Inter-Process Communication) na mesma máquina pode ser eficientemente realizada por meio de memória partilhada, conhecida como memória mapeada.
A memória mapeada em Java é um modelo que mapeia o conteúdo de um arquivo em uma área de memória virtual. Isso permite manipular a memória como um buffer normal, sem a necessidade de operações de leitura e escrita explícitas no arquivo. A disponibilidade do conteúdo na memória principal do processo pode variar, afetando o tempo de acesso aos dados.

  • A classe que suporta memória mapeada é o tipo MappedByteBuffer, que representa um buffer de acesso direto com conteúdo semelhante ao de um arquivo.
  • Tem a definição public abstract class MappedByteBuffer extends ByteBuffer
  • Instâncias de MappedByteBuffer são criadas com o método FileChannel.map e existem até serem eliminadas no processo.
  • Qualquer processo Java pode alterar o conteúdo de um MappedByteBuffer.
  • Se um MappedByteBuffer for truncado ou fechado por um processo, todos os processos não poderão mais acessá-lo, gerando uma exceção de acesso.
  • A manipulação de um MappedByteBuffer é exatamente igual à de um Buffer. Apenas adiciona os seguintes métodos:
    • MappedByteBuffer force() – obriga a atualização da memória secundária com o conteúdo do buffer.
    • boolean isLoaded() – indica se o conteúdo do buffer está em memória principal.
    • MappedByteBuffer load() – carrega o conteúdo do buffer em memória principal.

Pasted image 20230918155520.png

Exercicio: Implemente uma classe que permita a comunicação por memória partilhada entre processos JAVA no mesmo computador
...

A memória partilhada em JAVA é uma memória mapeada de um ficheiro que tem de ser conhecido dos vários processos através do path e nome do ficheiro. A classe para implementar a comunicação entre processos tem o nome “canalComunicacao”

public class canalComunicacao {
    // Ficheiro
    private File ficheiro;
    // Canal que liga o conteúdo do ficheiro ao Buffer
    private FileChannel canal;
    // Buffer
    private MappedByteBuffer buffer;
    // Dimensão máxima em bytes do buffer
    final int BUFFER_MAX = 30;

    // Construtor vazio
    public canalComunicacao() {
        ficheiro = null;
        canal = null;
        buffer = null;
    }

    // Abre o canal de comunicação
    public boolean abrirCanal() {
        // Cria um ficheiro com o nome "comunicacao.dat"
        ficheiro = new File("comunicacao.dat");
        // Cria um canal de comunicação de leitura e escrita
        try {
            canal = new RandomAccessFile(ficheiro, "rw").getChannel();
        } catch (FileNotFoundException e) {
            return false;
        }
        // Mapeia para memória o conteúdo do ficheiro
        try {
            buffer = canal.map(FileChannel.MapMode.READ_WRITE, 0, BUFFER_MAX);
        } catch (IOException e) {
            return false;
        }
        return true;
    }

    // Recebe uma mensagem convertendo-a numa String
    String receberMensagem() {
        String msg = new String();
        char c;
        buffer.position(0);
        while ((c = buffer.getChar()) != '\0')
            msg += c;
        return msg;
    }

    // Envia uma String como mensagem
    void enviarMensagem(String msg) {
        char c;
        buffer.position(0);
        for (int i = 0; i < msg.length(); ++i) {
            c = msg.charAt(i);
            buffer.putChar(c);
        }
        buffer.putChar('\0');
    }

    // Fecha o canal entre o buffer e o ficheiro
    void fecharCanal() {
        if (canal != null)
            try {
                canal.close();
            } catch (IOException e) {
                canal = null;
            }
    }
}

Consistência na informação
...