Função pthread_create na linguagem C

Função pthread_create na linguagem C

Conceitualmente, um programa é um único tópico que executa várias tarefas em série, uma após a outra.
O idioma C nos permite escrever programas multithreaded usando a biblioteca PTHread do padrão POSIX.
Um programa multithread é um tópico ou tarefa que é executada em paralelo e simultaneamente com o programa principal e outros tópicos abertos pelo mesmo programa em alguma parte dele.

Nisso Linux Dica Artigo, você aprenderá como criar um tópico a partir de um programa principal usando o pthread_create () função da biblioteca Pthread.

Isso explica o funcionamento teórico dessa função, seus argumentos de sintaxe, entrada e saída e o tipo de dados aceito em cada caso.
Em seguida, aplicaremos o que aprendemos em exemplos práticos, incluindo trechos e imagens de código, nos quais criamos e sincronizamos threads da função principal.

Sintaxe da função pthread_create () na linguagem C

int pthread_create (pthread_t *RESTRITE,
const pthread_attr_t *restringir att,
void *( *start_routine) (void *),
vazio *restringir arg);

Descrição da função pthread_create () na linguagem C

O pthread_create () A função cria um fio e o executa, em paralelo e simultaneamente com o programa que o criou. Esta função executa a rotina especificada por seu ponteiro na entrada start_routine Ao passar o argumento de entrada Arg.

Em seguida, vejamos os argumentos de entrada e saída de pthread_create () em detalhes, bem como uma descrição do trabalho, cada um desses argumentos executa dentro da função.

fio: Este é um argumento de saída que retorna o identificador do tópico criado. Este identificador é usado para referenciá -lo em certas funções de gerenciamento de threads, como pthread_join () ou pthread_cancel ().

attr: Esta entrada é o ponteiro de uma estrutura do tipo pthread_attr_t cujos membros especificam os atributos do novo thread. Quando esse argumento é enviado para NULL, os atributos do novo thread são levados com seus parâmetros padrão.

start_routine: Este é o ponteiro da função que será executada pelo novo thread.

Arg: Este é o ponteiro para o argumento de que a função principal passa para o novo tópico.

Se o tópico for criado com sucesso, pthread_create () retorna 0 como resultado. Se ocorrer um erro, ele retorna -1 e armazena na variável global errno o valor numérico específico representando esse erro.

O pthread_create () A função é definida no pThread.h cabeçalho. Para usá -lo, os seguintes cabeçalhos devem ser incluídos no “.Arquivo C ”, como mostrado abaixo:

#incluir
#incluir

Erros de compilação em programas com threads

Ao compilar programas GCC que usam threads, a compilação pode falhar se não for feita corretamente a partir da linha de comando.
A mensagem de erro mais comum emitida pelo compilador afirma que uma das funções do thread que nos referimos no código não está definida.

Esses erros geralmente resultam em desperdiçar tempo valioso verificando os cabeçalhos que inserimos no código, sua integridade e os diretórios associados ao compilador, pois tudo indica que o problema está lá.
Embora as funções que causam o erro sejam definidas no “pThread.H ”Cabeçalho e incluído no código, o compilador não reconhece essas funções, a menos que a biblioteca Pthread seja chamada da linha de comando durante a compilação.

Abaixo, você pode ver em verde a maneira correta de chamar a biblioteca PTHread do console de comando durante a compilação de programas com threads:

~ $ gcc -phread caminho/nome de arquivo.C -O out_name

Conforme mostrado na figura abaixo, o erro desaparece quando a biblioteca PTHread é chamada durante a compilação.

Como criar e executar um tópico com a função pthread_create () na linguagem C

Neste exemplo, explicaremos como pthread_create () funciona. Para fazer isso, criaremos uma função principal e a partir daí abrir um tópico que executa o Thread_function () função em paralelo com o função principal.

O código para este exemplo consiste em duas seções, o principal() função e o Thread_function () função, que é o tópico.
Em seguida, explicaremos cada uma das duas funções separadamente e depois as montaremos para compilar e executar o código.

Thread_function (): Esta função consiste em um para Loop com 5 ciclos, em cada um dos quais a mensagem "do thread" é ​​exibida no console de comando e após um atraso de 3 segundos, o ciclo é repetido novamente. A mensagem desta função é intercalada com a do principal() função para que você possa ver em tempo real o que cada um dos processos está fazendo simultaneamente.

Em seguida, nós vemos o nclusi o Thread_function () função e a definição de seu protótipo:

void* thread_function (void* n);
void* thread_function (void* n)

para (int a = 0; a!= 5; a ++)

printf (“do thread \ n”);
sono (3);

printf ("thread nclus \ n");
pthread_exit (n);

função principal: Neste exemplo, o principal() A função é Nclusióne para definir as variáveis ​​e criar o tópico.

O primeiro passo para criar um tópico é definir uma variável de tipo pthread_t que a NCL serve como o identificador do tópico. Neste exemplo, nós chamamos essa variável Thread_1.

Para Nclus the Thread, chamamos o pthread_create () Funcionar e passe o thread Identifier Thread_1 como o primeiro argumento.
Os atributos do segmento a ser criado são predefinidos neste caso, então o segundo argumento de entrada é nulo.
Como terceiro argumento, passamos o ponteiro para a função a ser executado no novo tópico, neste caso Thread_function ().
Como não precisamos passar nenhum argumento para o novo tópico neste exemplo, o ponteiro arg ncl também será nulo.

Depois de ligar pthread_create (), o novo thread começa a execução e a função principal() entra a para Loop de 5 ciclos, cada um dos quais imprime a mensagem "da função principal" aninhada com a mensagem "do tópico" da função Thread_function (). Após cada mensagem, um atraso de 3 segundos é inserido nos loops de ambas as funções antes que um novo ciclo seja iniciado.

Abaixo você pode ver o NCLUSI a função principal(), o nclusión dos cabeçalhos necessários e a declaração do protótipo da função Thread_function ():

#incluir
#incluir
#incluir
#incluir
void* thread_function (void* dados);
int main ()

pthread_t thread_1;
printf ("Criando o tópico… \ n");
pthread_create (& thread_1, null, thread_function, null);
para (int a = 0; a!= 5; a ++)

printf ("da função principal \ n");
sono (3);

sono (3);
retornar 0;

Em seguida, vemos o código completo para este exemplo. Copie e cole este fragmento em um arquivo com um “.Extensão C ”. Compilar o código e executá -lo para ver como o principal() função e o novo thread execute suas tarefas simultaneamente.

#incluir
#incluir
#incluir
#incluir
void* thread_function (void* dados);
int main ()

pthread_t thread_1;
printf ("Criando o tópico… \ n");
pthread_create (& thread_1, null, thread_function, null);
para (int a = 0; a!= 5; a ++)

printf ("da função principal \ n");
sono (3);

retornar 0;

/***************************************************** ****************/
void* thread_function (void* n)

para (int a = 0; a!= 5; a ++)

printf ("do thread \ n");
sono (3);

printf ("End of Thread \ n");
pthread_exit (n);

A imagem que vemos abaixo mostra a tarefa executada pelo tópico que criamos com o pthread_create () função em paralelo com a tarefa do principal() função, e as mensagens que cada uma delas envia para o console de comando:

Sincronização de threads na linguagem C

No código do exemplo anterior, o tempo de execução do tópico é mais curto que o do principal() função e, portanto, ambos fazem seu trabalho corretamente. Isso se deve ao atraso de 3 segundos que ocorre quando o principal() Função sai do loop.
No entanto, se os tempos de execução de um tópico forem mais longos que os dos principal() função e está totalmente executado, o programa termina e todos os threads que foram criados e ainda estão executando uma tarefa são fechados automaticamente.

Vamos ver o que acontece no código do exemplo anterior se definirmos um atraso de 1 segundo por ciclo no loop do principal() função e um dos 3 segundos no loop de thread.

Como mostrado na figura, o principal() função completou os 5 ciclos de seu para Loop, enquanto o tópico só conseguiu executar 3 ciclos antes do fechamento do programa.

O fechamento de um tópico sem executá-lo pode levar a problemas críticos em certos casos, pois pode estar armazenando dados gerados pelo usuário, escrevendo em um sistema de arquivos ou dispositivo de armazenamento ou executando alguma outra tarefa no momento da terminação.
Para evitar esses problemas, é importante desenvolver um mecanismo para "esperar" para que o tópico conclua a execução antes de fechar o programa ou executar uma tarefa. O pthread_join () A função interrompe a função que criou o segmento até que esse thread termine sua execução.

O pthread_join () Função leva dois argumentos de entrada. O primeiro é o identificador de thread retornado pelo pthread_create () função quando o encadeamento é criado e o segundo argumento é o ponteiro de uma variável que retorna o status de saída do thread.

Em seguida, usamos o código do exemplo anterior, mas substitua o para loop do principal() função com o pthread_join () função, como mostrado abaixo:

#incluir
#incluir
#incluir
#incluir
void* thread_function (void* dados);
int main ()

pthread_t thread_1;
printf ("Criando o tópico… \ n");
pthread_create (& thread_1, null, thread_function, null);
pthread_join (thread_1, nulo);
retornar 0;

/***************************************************** ****************/
void* thread_function (void* n)

para (int a = 0; a!= 5; a ++)

printf ("do thread \ n");
sono (3);

printf ("End of Thread \ n");
pthread_exit (n);

Nesse caso, o principal() A função apenas criará o tópico e aguardará que ele termine sua tarefa e feche o programa.

Possíveis erros que a função pthread_create () pode gerar e como reconhecê -los

O pthread_create () A função pode gerar vários erros, desde configurações inválidas de atributos até recursos insuficientes do sistema para o novo thread.
Quando uma função gera um erro, um código de identificação de erro numérico é armazenado na variável global errno. Esta variável e as definições numéricas para cada erro são definidas no “errno.H ”cabeçalho.
Abaixo está uma descrição de cada erro que pode ocorrer ao chamar o pthread_create () função e sua representação numérica definida em “Errno.h ".

Eagin: Não há recursos disponíveis para criar outro tópico. A representação numérica deste erro é 35.

Einval: A configuração de atributo no attr não é válida. A representação numérica deste erro é 22.

Eperm: Operação não permitida. Este erro ocorre quando você não possui permissões suficientes para definir os parâmetros de atributo no Att. A representação numérica deste erro é 1.

Conclusão

Nisso Linux Dica artigo, mostramos como usar o pthread_create () função para criar programas multitarefa com tópicos que executam em paralelo com a função principal.

Também dissemos como compilar programas que usam threads corretamente da linha de comando.
Também incluímos uma seção especial explicando a importância de levar em consideração os tempos de execução dos threads criados e ensinamos a sincronizar os threads com a função principal para alcançar sua execução correta.