Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么线程必须遵循外部或静态_C_Multithreading_Thread Safety_Thread Local Storage - Fatal编程技术网

C 为什么线程必须遵循外部或静态

C 为什么线程必须遵循外部或静态,c,multithreading,thread-safety,thread-local-storage,C,Multithreading,Thread Safety,Thread Local Storage,我正在阅读并将以下内容作为31-4的注释 如果变量的 声明 线程局部变量的声明可以包括初始值设定项,其方式与普通全局变量或静态变量相同 声明 C address(&)运算符可用于获取线程局部变量的地址 我想知道为什么关键字必须放在static或extern后面。没有它们就不能用吗 它的示例代码 /*************************************************************************\ * Copyr

我正在阅读并将以下内容作为31-4的注释

  • 如果变量的 声明
  • 线程局部变量的声明可以包括初始值设定项,其方式与普通全局变量或静态变量相同 声明
  • C address(&)运算符可用于获取线程局部变量的地址
我想知道为什么关键字必须放在
static
extern
后面。没有它们就不能用吗

它的示例代码

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2018.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* strerror_tls.c

   An implementation of strerror() that is made thread-safe through
   the use of thread-local storage.

   See also strerror_tsd.c.

   Thread-local storage requires: Linux 2.6 or later, NPTL, and
   gcc 3.3 or later.
*/
#define _GNU_SOURCE                 /* Get '_sys_nerr' and '_sys_errlist'
                                       declarations from <stdio.h> */
#include <stdio.h>
#include <string.h>                 /* Get declaration of strerror() */
#include <pthread.h>
#include "tlpi_hdr.h"


#define MAX_ERROR_LEN 256           /* Maximum length of string in per-thread
                                       buffer returned by strerror() */
/*   ||||||||||||||||||
//   vvvvvvvvvvvvvvvvvv
*/
    static     __thread      char buf[MAX_ERROR_LEN];
/* Thread-local return buffer */


char *
strerror(int err)
{
    if (err < 0 || err >= sys_nerr || sys_errlist[err] == NULL) {
        snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err);
    } else {
        strncpy(buf, sys_errlist[err], MAX_ERROR_LEN - 1);
        buf[MAX_ERROR_LEN - 1] = '\0';          /* Ensure null termination */
    }

    return buf;
}

static void *
threadFunc(void *arg)
{
    char *str;

    printf("Other thread about to call strerror()\n");
    str = strerror(EPERM);
    printf("Other thread: str (%p) = %s\n", str, str);

    return NULL;
}

int
main(int argc, char *argv[])
{
    pthread_t t;
    int s;
    char *str;

    str = strerror(EINVAL);
    printf("Main thread has called strerror()\n");

    s = pthread_create(&t, NULL, threadFunc, NULL);
    if (s != 0)
        errExitEN(s, "pthread_create");

    s = pthread_join(t, NULL);
    if (s != 0)
        errExitEN(s, "pthread_join");

    /* If strerror() is not thread-safe, then the output of this printf() be
       the same as that produced by the analogous printf() in threadFunc() */

    printf("Main thread:  str (%p) = %s\n", str, str);

    exit(EXIT_SUCCESS);
}
/*************************************************************************\
*版权所有(C)Michael Kerrisk,2018年*
*                                                                         *
*这个程序是自由软件。您可以使用、修改和重新发布它*
*根据*
*自由软件基金会,版本3或(按您的选择)任何*
*更高版本。本程序不提供任何保修。看*
*有关详细信息,请参阅COPYING.gpl-v3文件*
\*************************************************************************/
/*strerror_tls.c
strerror()的一个实现,通过
线程本地存储的使用。
另见strerror_tsd.c。
线程本地存储需要:Linux 2.6或更高版本、NPTL和
gcc 3.3或更高版本。
*/
#定义\u GNU\u SOURCE/*获取“\u sys\u nerr”和“\u sys\u errlist”
来自*/
#包括
#include/*获取strerror()的声明*/
#包括
#包括“tlpi_hdr.h”
#定义最大错误长度256/*每个线程中字符串的最大长度
strerror()返回的缓冲区*/
/*   ||||||||||||||||||
//VVVVVVVVV
*/
静态线程字符buf[MAX_ERROR_LEN];
/*线程本地返回缓冲区*/
煤焦*
strerror(内部错误)
{
if(err<0 | | err>=sys|nerr | | sys|errlist[err]==NULL){
snprintf(buf,最大错误,未知错误%d,错误);
}否则{
strncpy(buf,系统错误列表[err],最大错误长度-1);
buf[MAX_ERROR_LEN-1]='\0';/*确保空终止*/
}
返回buf;
}
静态空隙*
threadFunc(void*arg)
{
char*str;
printf(“其他线程即将调用strerror()\n”);
str=strerror(EPERM);
printf(“其他线程:str(%p)=%s\n”,str,str);
返回NULL;
}
int
main(int argc,char*argv[])
{
pthread_t;
int-s;
char*str;
str=strerror(EINVAL);
printf(“主线程已调用strerror()\n”);
s=pthread_create(&t,NULL,threadFunc,NULL);
如果(s!=0)
errExitEN(s,“pthread_create”);
s=pthread_join(t,NULL);
如果(s!=0)
errExitEN(s,“pthread_join”);
/*如果strerror()不是线程安全的,则此printf()的输出可能是
与threadFunc()中类似的printf()生成的相同*/
printf(“主线程:str(%p)=%s\n”,str,str);
退出(退出成功);
}

重新阅读您引用的文本(强调我的):

  • 如果变量的声明中指定了static或extern关键字,则_thread关键字必须紧跟在static或extern关键字之后
因此,如果两者均未指定,则本条款不适用


至于“为什么”,如果这个说法是真的(我怀疑它大概是真的,但说得不准确),那么这只是“GNUC”的语法问题,GNUC是从哪里来的。您可以在C11标准中查找等效
\u Thread\u local
的语法要求。

线程局部变量的标准C存储类说明符为。该标准还规定:

6.11.5存储类别说明符

存储类说明符在声明开头以外的位置 声明中的说明符是过时的特性

因此,该标准规定存储类关键字(
static
extern
auto
-不要使用它!-
register
-同上-
\u Thread\u local
typedef
)应该出现在声明的开头。当出现
static
extern
\u Thread\u local
时,本书建议将
static
extern
放在第一位,将
\u Thread\u local
放在第二位

当然,这本书使用的是
\uuThread
,而不是
\uThread\uLocal
。这是一个特定于编译器(实现)的关键字,其行为类似于标准C
\u Thread\u local
和Microsoft的
\u declspec(Thread)

GCC关于文件的文件(重点增加):

在用户级别,可以通过一个新的存储类关键字看到扩展名:
\uuu thread
。例如:

__thread int i;
extern __thread struct state s;
static __thread char *p;
\u线程
说明符可以单独使用,与
外部
静态
说明符一起使用,但不与其他存储类说明符一起使用。当与
extern
static
一起使用时,
\uuu线程
必须紧跟在其他存储类说明符之后。

\u线程
说明符可应用于类的任何全局、文件范围静态、函数范围静态或静态数据成员。它不能应用于块作用域自动或非静态数据成员

因此,您看到的是特定于GCC的线程本地存储表示法,正如我所指出的和GCC手册所指出的,存储类信息应该在声明中放在第一位(GCC明确表示
\uu thread
之后