C / C de problèmes de traitement et de sécurité multithread de errno

Dans le langage C, car je crois que le stockage des codes d'erreur errno variable globale, tout le monde connaît. Pour éviter toute confusion et de la valeur de rendement normal, le système ne généralement pas appeler directement renvoie un code d'erreur, mais le code d'erreur (une valeur entière, des valeurs différentes représentent des significations différentes) dans une variable globale appelée errno dans, errno les messages d'erreur représentent des valeurs différentes définies dans le fichier <errno.h>. Si un appel système ou un appel de fonction bibliothèque échoue, il est possible de déterminer la cause du problème, ce qui suggère que la valeur de errno erreur de procédure en lecture, ce qui est une méthode importante de débogage d'un programme.

Avec perror et la fonction strerror, vous pouvez facilement voir les détails de l'erreur. où:

  • perror défini dans <stdio.h>, un code d'erreur et pour l'impression d'un message de description;
  • strerror définie dans <string.h>, un message pour l'acquisition du code d'erreur correspondant à la description;

Il faut d'abord être effacé avant d'appeler errno.

Dans le langage C, ou si les fonctions de la bibliothèque d'appels de système sont effectuées correctement, alors la valeur de errno n'est pas effacée. En d'autres termes, la valeur de errno ne sera réglé à une erreur appel de fonction bibliothèque se produit lorsque l'appel de fonction de bibliothèque d'exécution est réussie, la valeur de errno n'est pas modifié, bien sûr, ne prendra pas l'initiative est réglé sur 0. Précisément à cause de cela, il y aura de nombreux problèmes dans les diagnostics d'erreur de programmation réelle.

Par exemple:

/// @file main.cpp
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    /*调用errno之前必须先将其清零*/
    errno=0;
    FILE *fp = fopen("test.txt","r");
    if(errno!=0)
    {
        printf("errno值: %d\n",errno);
        printf("错误信息: %s\n",strerror(errno));
    }
    fp = fopen("main.cpp","r");
    if(errno!=0)
    {
        printf("errno值: %d\n",errno);
        printf("错误信息: %s\n",strerror(errno));
    }
    fclose(fp);
    return 0;
}

sortie:

$ g++ main.cpp -o main
$ ./main
errno值: 2
错误信息: No such file or directory
errno值: 2
错误信息: No such file or directory

Évitez Redéfinir errno.

Pour errno, qui est une norme par l'ISO C et POSIX défini symboles. Plus tôt, la norme POSIX sera jamais est errno défini comme « extern int errno » cette forme, mais maintenant définir la façon dont ce relativement rare, il est parce que errno Cela prend la forme de multithreading est fatale.

Dans un environnement multithread, errno variable est partagée par plusieurs threads, de sorte qu'il peut conduire à ce qui suit: Un fil est changé errno valeur de certaines erreurs, puis enfilez B, même si aucune erreur a eu lieu, mais quand il détecte errno lorsque la valeur du fil B pensera aussi qu'ils erreur est survenue.

Nous savons que dans un environnement multithread, plusieurs threads partagent l'espace d'adressage du processus, et il faut donc que chaque fil doit avoir leur propre errno locale pour éviter un autre thread une interférence de fil. En fait, maintenant la plupart par le compilateur sont errno ensemble pour obtenir sous forme de variables locales de fil pour assurer la cause de l'erreur entre chaque fil de chaîne ne change pas.

Par exemple, dans le cas du compilateur GCC Linux, la définition de la norme errno « /usr/include/errno.h » comme suit:

/* Get the error number constants from the system-specific file.
   This file will test __need_Emath and _ERRNO_H.  */
#include <bits/errno.h>
#undef   __need_Emath
#ifdef   _ERRNO_H
/* Declare the `errno' variable, unless it's defined as a macro by bits/errno.h.  This is the case in GNU, where it is a per-thread variable.  This redeclaration using the macro still works, but it will be a function declaration without a prototype and may trigger a -Wstrict-prototypes warning.  */
#ifndef   errno
extern int errno;
#endif

Dans laquelle errno incorporé dans le fichier « /usr/include/bits/errno.h » est suit comme:

# ifndef __ASSEMBLER__
/* Function to get address of global 'errno' variable.  */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads,errno is a per-thread value.  */
# define errno (*__errno_location ())
# endif
# endif /* !__ASSEMBLER__ */
# endif /* _ERRNO_H */

Ainsi, par "extern int * __ errno_location (void), __ THROW__attribute __ ((__ const__));" et "#define errno (* __ errno_location ())" est défini, de sorte que chaque fil a sa propre errno, quel que soit le fil à errno modifier sont de modifier leurs propres variables locales, de manière à atteindre thread-safe.

Évitez d'utiliser errno vérifier l'erreur de flux de fichiers.

Comme nous l'avons expliqué précédemment, dans la norme POSIX, errno valeurs peuvent être vérifiées en appelant la fonction fopen si une erreur est survenue. Cependant, les opérations de flux de fichiers spécifiques de pour vérifier si l'erreur doit être utilisé fonction ferror, sans pouvoir utiliser errno pour le contrôle d'erreur de flux de fichiers. Le code exemple suivant:

int main(void)
{
    FILE* fp=NULL;
    /*调用errno之前必须先将其清零*/
    errno=0;
    fp = fopen("Test.txt","w");
    if(fp == NULL)
    {
        if(errno!=0)
        {
            /*处理错误*/
        }
    }
    else
    {
        /*错误地从fp所指定的文件中读取一个字符*/
        fgetc(fp);
        /*判断是否读取出错*/
        if(ferror(fp))
        {
            /*处理错误*/
            clearerr(fp);
        }
        fclose(fp);
        return 0;
    }
}
Publié 257 articles originaux · louange gagné 13 · vues + 60000

Je suppose que tu aimes

Origine blog.csdn.net/LU_ZHAO/article/details/105119476
conseillé
Classement