Tornando variáveis estáticas globais multithread seguras
-
27-09-2019 - |
Pergunta
Tenho variáveis estáticas globais em uma biblioteca C, que geram exceções em uma execução multithread.Preciso torná-los seguros de alguma forma (ou seja, cada thread deve estar relacionado a uma instância diferente dessas variáveis).Algum método recomendado?
Solução
Não existe uma maneira padrão que funcione em todas as implementações C, mas existem soluções específicas para implementações.Por exemplo, com o compilador da Microsoft (veja os documentos),
__declspec( thread ) int tls_i = 1;
faz tls_i
reside no armazenamento local de thread (cada thread tem sua própria instância separada desta variável).Com gcc, a sintaxe é
__thread int tls_i;
Você também pode querer verificar o entrada da Wikipédia sobre o assunto.
Outras dicas
Primeira pergunta:
- os threads precisam de suas próprias cópias das variáveis?
- ou eles precisam coordenar o acesso a uma única cópia compartilhada?
Se você precisar do primeiro, as outras respostas fizeram sugestões sobre 'armazenamento local de thread'.
Se você precisar do último, então, de uma forma ou de outra, você precisa garantir que haja um mutex apropriado nessas variáveis (o escopo do mutex é um dos problemas que você enfrenta) e que todos os threads usam o mutex e liberam o mutex.Isso é mais complicado.Pode até ser que você precise fornecer funções que controlem o acesso às variáveis.
A variável padrão errno
pode ser um lvalue modificável:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
Em um aplicativo threaded (compilado com -DREENTRANT), é isso que acontece;no MacOS X, parece que é o que acontece de qualquer maneira (eles usam o nome __error
em vez de _errno_func
;ambos estão no namespace da implementação).
Você pode querer, ou acabar tendo que fazer algo semelhante para suas variáveis.O fato de você dizer que eles são estáticos melhora um pouco as coisas.Você só tem um arquivo para lidar (a menos que seja descuidado o suficiente para passar de volta - ou em - ponteiros para essas variáveis).
O que você precisava é TLS (armazenamento local de thread), que também é conhecido como dados específicos do thread ou dados privados do thread.Esse mecanismo pode garantir que cada thread acesse sua própria cópia separada de dados, sem se preocupar em sincronizar o acesso com outros threads.
Existem dois métodos para usar TLS:
implícito:usando palavra-chave
Janelas: __declspec(thread) int tls_var = 10;
Linux com GCC: __thread int tls_var = 10
explícito:usando API específica relacionada a TLS
Janelas:
- TlsAlloc(): alocar memória para dados tls
- TlsFree(): liberar a memória dos dados tls
- TlsSetValue(): definir o valor de tls
- TlsGetValue(): obter o valor de tls
Consulte o MSDN para obter informações detalhadas.
Linux com GCC:
- pthread_key_create():crie os dados tls
- pthread_key_delete():destruir os dados tls
- pthread_getspecific():obter o valor de tls
- pthread_setespecífico():definir o valor de tls
A maioria dos compiladores tem alguma maneira de designar armazenamento local de thread.Supondo que esteja disponível, é isso que você deseja.