• strerror线程安全分析


    导读

    strerror是否线程安全了? 1

    errno是否线程安全? 1

    1strerror源码 2

    2__strerror_r源码 2

    strerror是否线程安全了?

    答案是NO,但它有个线程安全的版本:strerror_r。借助Linuxman,即可看到详情:

    #include <string.h>

    char *strerror(int errnum);

    int strerror_r(int errnum, char *buf, size_t buflen); /* GNU-specific */

    那么,在多线程中使用strerror是否安全了?答案是不一定,一定情况下也是非常安全的。

    不安全会造成内存违规访问吗?也就是会发生SIGSEGV吗?答案是NO,仍是内存安全的,但是可能会返回错乱的字符串。

    那么,在多线程程序中,什么情况下使用strerror是绝对安全的了?如果参数errnum是一个已知的errno,则使用strerror是绝对安全的,也就是会返回期待的字符串,而不会出现乱码

    对比strerror源码,是因为strerror会在下述直接返回:

      if (__builtin_expect (ret != NULL, 1))

        return ret;

    而这走的是_strerror_r中的分支:

    return (char *) _(_sys_errlist_internal[errnum]);

    errno是否线程安全?

    答案是不一定,取决于编译宏:

    #  if !defined _LIBC || defined _LIBC_REENTRANT

    /* When using threads, errno is a per-thread value.  */

    #   define errno (*__errno_location ())

    #  endif

    可以通过下段小代码,来确定默认时是否有定义,如果没有,则需要在编译时加上:

    #include <stdio.h>

    int main()

    {

            #ifdef _GNU_SOURCE

                    printf("_GNU_SOURCE defined ");

            #else

                    printf("_GNU_SOURCE not defined ");

            #endif

            #ifdef _LIBC_REENTRANT

                    printf("_LIBC_REENTRANT defined ");

            #else

                    printf("_LIBC_REENTRANT not defined ");

            #endif

            #ifdef _LIBC

                    printf("_LIBC defined ");

            #else

                    printf("_LIBC not defined ");

            #endif

            return 0;

    }

    1strerror源码

    // glibc-2.14stringstrerror.c

    #include <errno.h>

    /* Return a string describing the errno code in ERRNUM.

       The storage is good only until the next call to strerror.

       Writing to the storage causes undefined behavior.  */

    libc_freeres_ptr (static char *buf);

    char *

    strerror (errnum)

         int errnum;

    {

      char *ret = __strerror_r (errnum, NULL, 0);

      int saved_errno;

      if (__builtin_expect (ret != NULL, 1))

        return ret;

     

      saved_errno = errno;

      if (buf == NULL)

        buf = malloc (1024);

      __set_errno (saved_errno);

      if (buf == NULL)

        return _("Unknown error");

      return __strerror_r (errnum, buf, 1024);

    }

    2__strerror_r源码

    // glibc-2.14string\_strerror.c

    /* Return a string describing the errno code in ERRNUM.  */

    char *

    __strerror_r (int errnum, char *buf, size_t buflen)

    {

      if (__builtin_expect (errnum < 0 || errnum >= _sys_nerr_internal

    || _sys_errlist_internal[errnum] == NULL, 0))

        {

          /* Buffer we use to print the number in.  For a maximum size for

     `int' of 8 bytes we never need more than 20 digits.  */

          char numbuf[21];

          const char *unk = _("Unknown error ");

          size_t unklen = strlen (unk);

          char *p, *q;

          bool negative = errnum < 0;

          numbuf[20] = '';

          p = _itoa_word (abs (errnum), &numbuf[20], 10, 0);

          /* Now construct the result while taking care for the destination

     buffer size.  */

          q = __mempcpy (buf, unk, MIN (unklen, buflen));

          if (negative && unklen < buflen)

    {

      *q++ = '-';

      ++unklen;

    }

          if (unklen < buflen)

    memcpy (q, p, MIN ((size_t) (&numbuf[21] - p), buflen - unklen));

          /* Terminate the string in any case.  */

          if (buflen > 0)

    buf[buflen - 1] = '';

          return buf;

        }

      return (char *) _(_sys_errlist_internal[errnum]);

    }

    weak_alias (__strerror_r, strerror_r)

    libc_hidden_def (__strerror_r)

  • 相关阅读:
    Python中下划线---完全解读(转)
    数字、基数及表示
    实现二叉排序树的各种算法
    shell脚本 空格
    Linux中执行shell脚本的4种方法
    vim常用命令总结
    Linux 奇技淫巧
    排序算法之二分治法
    二分查找
    排序算法之一插入排序
  • 原文地址:https://www.cnblogs.com/aquester/p/9891626.html
Copyright © 2020-2023  润新知