Na Imagem: SO gerenciando memória, CPU e I/O para três processos diferentes. Fonte: OER OS
Na Imagem: Applicação com dois processos, cada processo com múltiplas threads. Fonte: OER OS
A thread é criada com pthread_create
e esperada com pthread_join
.
#include <stdio.h>
#include <pthread.h>
void *thread_function(void *arg) {
printf("Olá do thread!\n");
pthread_exit(0);
}
int main() {
pthread_t thread1;
pthread_create(&thread1, NULL, thread_function, NULL);
pthread_join(thread1, NULL);
return 0;
}
fork()
fork()
, o processo-filho é uma cópia do processo-pai.
//pidouzero.c
int main(int argc, char *argv[]) {
printf("Hello, world!\n");
pid_t pid = fork();
printf("fork retornou %d\n", pid);
return 0;
}
$ ./pidouzero
Hello, world!
fork retornou 1111
fork retornou 0
fork()
Cópia do processo-pai pela função fork()
. Fonte: OER OS
fork()
(cont.)fork()
é chamada uma vez, mas retorna duas vezes:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
pid_t pid = fork(); //Cria processo-filho
if (pid < 0){
printf("Erro ao criar processo.\n")
}
else if (pid == 0){
printf("Eu sou o filho.\n");
exit(1); //Encerra o processo
}
else {
printf("Eu sou o pai.\n");
wait(NULL); //Espera o processo-filho encerrar
}
return 0;
}
Quantos processos são criados, incluindo o processo-pai?
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
fork();
fork();
fork();
return 0;
}
Note que não podemos assumir a ordem de execução dos processos. O SO decide a ordem de execução com base em seu algoritmo de escalonamento (aula futura).
exec()
A função exec()
é uma syscall usada depois do fork()
para carregar um novo programa na memória do processo-filho.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid t pid;
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
execlp("/bin/ls","ls",NULL);
}
else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
printf("Child Complete");
}
return 0;
}
exit()
.
exit(1);
exit()
pode ser chamada diretamente (comoreturn
emmain()
.wait()
.
wait()
recebe um parâmetro que permite que o pai obtenha o statusint status; pid = wait(&status);
wait()
, porque a tabela dewait()
, é conhecido como processo zumbi.wait()
, o identificador do processo zumbi e suawait()
e, em vez disso, foi encerrado é chamado de proceso órfão.Conforme threads e processos executam, eles mudam de estado:
Fonte da Imagem: OER OS
Fonte da Imagem: Julia Evans.
Fonte da Imagem: Julia Evans.
O nome "Ada" é passado como um argumento da função thread_function
. É importante o cast do void *
para char *
para acessar o argumento corretamente.
#include <stdio.h>
#include <pthread.h>
void *thread_function(void *arg) {
char *name = (char *)arg; // Cast do argumento para char*
printf("Olá, %s!\n", name);
pthread_exit(0);
}
int main() {
pthread_t thread1;
pthread_create(&thread1, NULL, thread_function, "Ada"); // Passa o nome como argumento
pthread_join(thread1, NULL);
return 0;
}
#include <stdio.h>
#include <pthread.h>
#include <unistd.h> // Para sleep()
void *print_message(void *arg) {
int thread_id = (int)(long)arg; /* Cast para obter o ID da thread */
printf("Thread %d: Olá do thread!\n", thread_id);
sleep(1); /* Pausa a execução da thread por 1 segundo */
printf("Thread %d: Thread terminando...\n", thread_id);
pthread_exit(0);
}
int main() {
pthread_t threads[5]; /* Declara um array de threads (pthread_t) para armazenar os IDs das threads criadas */
int thread_ids[5];
/* Cria 5 threads */
for (int i = 0; i < 5; i++) {
thread_ids[i] = i + 1; /* Atribui um ID único para cada thread */
pthread_create(&threads[i], NULL, print_message, (void *)thread_ids[i]);
}
/* Faz com que o programa principal espere até que as threads sejam finalizadas antes de continuar a execução */
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
printf("Programa principal terminado.\n");
return 0;
}
Compilando o Código e Executando o Programa
gcc -c multiple_threads.c
gcc -o multiple_threads multiple_threads.o
./multiple_threads
Saída possível (a ordem em que as mensagens são impressas pode variar devido à natureza concorrente das threads)
Thread 1: Olá do thread!
Thread 2: Olá do thread!
Thread 3: Olá do thread!
Thread 4: Olá do thread!
Thread 5: Olá do thread!
Thread 1: Thread terminando...
Thread 2: Thread terminando...
Thread 3: Thread terminando...
Thread 4: Thread terminando...
Thread 5: Thread terminando...
Programa principal terminado.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *increment_counter(void *arg) {
int *iptr = (int *)malloc(sizeof(int));
*iptr = 0;
for (int i = 0; i <= 10; i++){
(*iptr)++;
}
return iptr;
}
int main() {
pthread_t thread1;
int *resultado;
pthread_create(&thread1, NULL, increment_counter, NULL);
//pthread_join permite acessar o retorno da função da thread
pthread_join(thread1, (void *)&resultado);
printf("Thread retornou o valor %d\n", *resultado);
return 0;
}