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