2013-08-02 1 views
1

J'essaie de comprendre comment la glibc initialise errno sans le préprocesseur en remplaçant le symbole errno.Comment errno thread-safe est-il initialisé si #define remplace le symbole errno?

J'ai d'abord essayé de mettre en œuvre une version simple moi-même basée sur csu/errno-loc.c et csu/errno.c:

myerrno.h

#ifndef MYERRNO_H 
#define MYERRNO_H 

extern int *myerrno_location(void); 
#define myerrno (*myerrno_location()) 

#endif 

myerrno.c

#include "myerrno.h" 

static int myerrno = 0; 

int *myerrno_location(void){ 
    return &myerrno; 
} 

Toutefois, lorsque J'essaie de compiler je reçois l'erreur suivante m essages:

myerrno.c:3:1: error: function ‘myerrno_location’ is initialized like a variable 
myerrno.c:3:12: error: static declaration of ‘myerrno_location’ follows non-static declaration 
myerrno.h:4:13: note: previous declaration of ‘myerrno_location’ was here 

Je peux dire que le préprocesseur est substituait (*myerrno_location(void)) lorsqu'il rencontre myerrno sur la ligne 3 - et naturellement ce comportement est normal. Je ne comprends pas pourquoi ce n'est pas un problème pour glibc. Comment les implémentations thread-safe de errno contourner ce problème de substitution de préprocesseur sans renommer la variable statique errno?

+0

ce fil est-il utile? http://stackoverflow.com/questions/1694164/is-errno-thread-safe – DRC

+0

Dans le code threadé, il n'y a pas un seul emplacement pour une variable 'errno'; il y a une variable par thread, et la fonction cachée derrière la macro est responsable de renvoyer un pointeur vers la variable spécifique au thread. –

+0

@JonathanLeffler Les variables statiques sont-elles partagées entre les threads? –

Répondre

3

Résoudre votre problème est aussi simple que de changer le nom de votre variable statique.

static int myerrno_variable = 0; 

int *myerrno_location(void){ 
    return &myerrno_variable; 
} 

Notez que votre version est thread toujours pas sûr car toutes les discussions ont accès à la même myerrno_variable. Une implémentation réelle renvoie un emplacement de mémoire spécifique au thread. Dans GCC, il existe une extension qui fournit la classe de stockage __thread. C.11 fournit sa propre version de celle appelée thread_local, mais elle n'est disponible que si le support du thread est fourni par l'implémentation (ce qui peut être vérifié en regardant si __STDC_NO_THREADS__ est défini ou non).

static __thread int myerrno_variable_gcc;  /* if using GCC */ 
static thread_local int my_errno_variable_c11; /* if __STD_NO_THREADS__ isn't defined */ 

Sur un système sans fil Posix fonction locale, une mise en œuvre pourrait utiliser pthread_getspecific() pour obtenir un pointeur sur fil de données spécifique qui a été allouée pour chaque fil, et mis à pthread_setspecific(). Voir the manual pour plus d'informations.

+0

Donc ** glibc ** est capable d'utiliser le même nom car il utilise l'extension GCC '__thread', alors que la plupart des autres implémentations renomment simplement la variable? –

+0

@VilhelmGray: La plupart des implémentations ont probablement une extension similaire, puisque la fonctionnalité a été ajoutée à la norme C.11. Cependant, même si ce n'était pas le cas, POSIX fournit toujours un mécanisme d'allocation de stockage spécifique au thread. – jxh

+0

@VilhelmGray: Oh, ** glibc ** le corrige probablement de la même manière que je vous l'avais dit pour le réparer. Il n'utiliserait pas le même nom pour la variable et la macro comme ça. L'extension '__thread' permet à chaque thread d'avoir sa propre variable privée à laquelle le thread peut se référer par le même nom. – jxh