Leitores como você ajudam a apoiar o MUO. Quando você faz uma compra usando links em nosso site, podemos ganhar uma comissão de afiliado. Consulte Mais informação.

No Linux, você pode criar e gerenciar encadeamentos em C/C++ usando a biblioteca de encadeamento POSIX (pthread). Ao contrário de outros sistemas operacionais, há pouca diferença entre um thread e um processo no Linux. É por isso que o Linux geralmente se refere a seus threads como processos leves.

Usando a biblioteca pthread, você pode criar threads, esperar que eles terminem e finalizá-los explicitamente.

A história do uso de threads no Linux

Antes do Linux versão 2.6, a implementação do encadeamento principal era LinuxThreads. Esta implementação teve limitações significativas em termos de desempenho e operações de sincronização. Um limite no número máximo de threads que poderiam ser executados os restringia a 1000s.

Em 2003, uma equipe liderada por desenvolvedores da IBM e RedHat conseguiu fazer o Biblioteca de threads POSIX nativa

(NPTL) projeto disponível. Foi introduzido pela primeira vez no RedHat Enterprise versão 3 para resolver problemas de desempenho com a Java Virtual Machine no Linux. Hoje, a biblioteca GNU C contém implementações de ambos os mecanismos de encadeamento.

Nenhuma delas é uma implementação de threads verdes, que uma máquina virtual gerenciaria e executaria em modo puramente de usuário. Quando você usa a biblioteca pthread, o kernel cria um thread toda vez que um programa é iniciado.

Você pode encontrar informações específicas do thread para qualquer processo em execução nos arquivos em /proc//task. Este é o local padrão para informações de processo em o padrão procfs Linux. Para aplicativos de thread único, parecerá que há um registro de tarefa com o mesmo valor do PID neste diretório.

Lógica de Trabalho de Threads

Threads são como processos atualmente em execução no sistema operacional. Em sistemas de processador único (por exemplo, microcontroladores), o kernel do sistema operacional simula threads. Isso permite que as transações sejam executadas simultaneamente por meio do fatiamento.

Um sistema operacional single-core só pode realmente executar um processo por vez. No entanto, em sistemas multi-core ou multi-processador, esses processos podem ser executados simultaneamente.

Criação de Threads em C

Você pode usar o pthread_create função para criar um novo segmento. O pthread.h O arquivo de cabeçalho inclui sua definição de assinatura junto com outras funções relacionadas ao encadeamento. Os threads usam o mesmo espaço de endereço e descritores de arquivo do programa principal.

A biblioteca pthread também inclui o suporte necessário para mutex e operações condicionais necessárias para operações de sincronização.

Ao usar as funções da biblioteca pthread, você deve garantir que o compilador vincule o pthread biblioteca em seu executável. Se necessário, você pode instruir o compilador a vincular à biblioteca usando o -eu opção:

gcc-o teste test_thread.c -lpthread

A função pthread_create tem a seguinte assinatura:

intpthread_create(pthread_t *fio, constpthread_attr_t *atr, vazio *(*início_rotina)(vazio *), vazio *arg)

Ele retorna 0 se o procedimento for bem-sucedido. Se houver um problema, ele retornará um código de erro diferente de zero. Na assinatura da função acima:

  • O fio parâmetro é do tipo pthread_t. O thread criado estará sempre acessível com esta referência.
  • O atrair O parâmetro permite especificar um comportamento personalizado. Você pode usar uma série de funções específicas de thread começando com pthread_attr_ para configurar este valor. As personalizações possíveis são a política de agendamento, o tamanho da pilha e a política de desanexação.
  • start_routine especifica a função que o thread executará.
  • arg representa uma estrutura de dados genérica passada para a função pelo thread.

Aqui está um exemplo de aplicação:

#incluir
#incluir
#incluir
#incluir

vazio *trabalhador(vazio *dados)
{
Caracteres *nome = (Caracteres*)dados;

para (int eu = 0; eu < 120; i++)
{
você dorme(50000);
printf("Olá do nome do tópico = %s\n", nome);
}

printf("Tópico %s concluído!\n", nome);
retornarNULO;
}

intprincipal(vazio)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabalhador, "X");
pthread_create(&th2, NULO, trabalhador, "Y");
dormir(5);
printf("Sair do programa principal\n");
retornar0;
}

Tipos de rosca

Quando um thread retorna do principal() função em um aplicativo, todos os threads terminam e o sistema libera todos os recursos usados ​​pelo programa. Da mesma forma, ao sair de qualquer thread com um comando como um saída(), seu programa encerrará todos os threads.

Com o pthread_join função, você pode esperar que um encadeamento seja encerrado. O thread que usa essa função será bloqueado até que o thread esperado termine. Os recursos que utilizam do sistema não são devolvidos mesmo em casos como o encerramento de threads joinable, não escalonadas pela CPU, ou mesmo falha na junção com pread_join.

Às vezes, há situações em que unir com pthread_join não faz sentido; se for impossível prever quando o thread terminará, por exemplo. Nesse caso, você pode garantir que o sistema retorne todos os recursos automaticamente no ponto em que o thread retorna.

Para conseguir isso, você deve iniciar os tópicos relevantes com o SEPARADO status. Ao iniciar um tópico, SEPARAR status pode ser definido por meio de valores de atributo de encadeamento ou com o pthread_detach função:

intpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
intpthread_detach(pthread_t fio);

Aqui está um exemplo de uso de pthread_join(). Substitua a função principal no primeiro programa pelo seguinte:

intprincipal(vazio)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabalhador, "X");
pthread_create(&th2, NULO, trabalhador, "Y");
dormir(5);
printf("saindo do programa principal\n");
pthread_join (th1, NULO);
pthread_join (th2, NULO);
retornar0;
}

Quando você compilar e executar o programa, sua saída será:

Olá do tópico Y
Olá do tópico X
Olá do tópico Y
...
Olá do tópico Y
saindo do programa principal
Olá do tópico X
...
Olá do tópico X
Tópico X concluído!
Olá do tópico Y
Tópico Y concluído!

Término do Tópico

Você pode cancelar um thread com uma chamada para pthread_cancel, passando o correspondente pthread_t eu ia:

intpthread_cancel(pthread_t fio);

Você pode ver isso em ação no código a seguir. Novamente, apenas o principal função é diferente:

intprincipal(vazio)
{
pthread_t th1, th2;
pthread_create(&th1, NULO, trabalhador, "X");
pthread_create(&th2, NULO, trabalhador, "Y");
dormir(1);
printf("> Cancelando Thread Y!!\n");
pthread_cancel (th2);
você dorme(100000);
printf("> Cancelando Thread X!\n");
pthread_cancel (th1);
printf("saindo do programa principal\n");
retornar0;
}

Por que os tópicos são criados?

Os sistemas operacionais sempre tentam executar encadeamentos em uma ou mais CPUs, seja de uma lista autocriada ou de uma lista de encadeamentos criada pelo usuário. Alguns threads não podem ser executados porque estão aguardando um sinal de entrada/saída do hardware. Eles também podem estar esperando voluntariamente, aguardando uma resposta de outro encadeamento, ou ter outro encadeamento bloqueando-os.

Você pode ajustar os recursos que aloca aos encadeamentos criados usando pthread. Isso pode ser uma política de agendamento personalizada ou você pode escolher algoritmos de agendamento, como FIFO ou Round-robin, se desejar.