Use variáveis thread_local em C
-
Use o tipo
_Thread_local
para declarar variável com duração de armazenamento de thread -
Use o tipo
thread_local
para declarar variável com duração de armazenamento de thread
![Use variáveis thread_local em C](/img/C/feature-image---thread_local-in-c.webp)
Este artigo irá explicar vários métodos de como usar variáveis thread_local
em C.
Use o tipo _Thread_local
para declarar variável com duração de armazenamento de thread
A linguagem C define várias palavras-chave para diferentes classes de armazenamento como auto
, static
, register
, extern
. Desde a especificação do padrão C11, o especificador _Thread_local
foi adicionado. A duração do armazenamento _Thread_local
começa no momento da criação da thread e termina com o seu término. O valor armazenado no objeto _Thread_local
é inicializado quando o encadeamento é iniciado e limpo quando o encadeamento termina. Em geral, os objetos de segmento local são outra alternativa para evitar condições de corrida em recursos compartilhados. Ou seja, separamos implicitamente os dados entre os encadeamentos, pois os objetos qualificados _Thread_local
têm instâncias separadas para cada encadeamento.
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
_Thread_local int counter = 0;
enum { MAX_ITER = 10000 };
void *incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
return (void *)counter;
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc, sum = 0;
for (int i = 0; i < NUM_THREADS; ++i) {
rc = thrd_create(&threads[i], (thrd_start_t)incrementCounter, (void *)i);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
int retval;
for (int i = 0; i < NUM_THREADS; ++i) {
thrd_join(threads[i], &retval);
sum += retval;
}
printf("count = %d\n", sum);
thrd_exit(EXIT_SUCCESS);
}
Resultado:
thread 1 started incrementing ID - 140162648991488
thread 0 started incrementing ID - 140162657384192
thread 2 started incrementing ID - 140162640598784
thread 3 started incrementing ID - 140162632206080
count = 40000
Use o tipo thread_local
para declarar variável com duração de armazenamento de thread
Alternativamente, a linguagem C define uma expressão macro thread_local
para denotar o especificador como _Thread_local
. Observe que as variáveis thread_local
devem ser declaradas em um escopo de arquivo para serem visíveis a todos os encadeamentos, ou o usuário pode incluir explicitamente um especificador static
também para expandir seu escopo para o nível de arquivo. A estrutura do programa precisará ser modificada, pois as threads devem comunicar os valores dos objetos thread_local
para a thread principal. O código de exemplo anterior que implementa o programa de contador simples deve ser modificado para passar os valores de contador incrementados de volta ao encadeamento de chamada. Portanto, precisamos utilizar a função thrd_join
e seu segundo argumento que armazena o valor de retorno da rotina de thread. Lembre-se de que todos os valores incrementados devem ser somados na thread principal, que também é responsável por imprimir o resultado final no stdout
.
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
thread_local int counter = 0;
enum { MAX_ITER = 10000 };
void *incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
return (void *)counter;
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc, sum = 0;
for (int i = 0; i < NUM_THREADS; ++i) {
rc = thrd_create(&threads[i], (thrd_start_t)incrementCounter, (void *)i);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
int retval;
for (int i = 0; i < NUM_THREADS; ++i) {
thrd_join(threads[i], &retval);
sum += retval;
}
printf("count = %d\n", sum);
thrd_exit(EXIT_SUCCESS);
}
Resultado:
thread 1 started incrementing ID - 140162648991488
thread 2 started incrementing ID - 140162640598784
thread 0 started incrementing ID - 140162657384192
thread 3 started incrementing ID - 140162632206080
count = 40000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook