为什么必须 __thread 跟随 extern 或 static
Why must __thread follow extern or static
我正在阅读 Kerrisk's book 并看到以下内容作为 31-4 的注释,
- The
__thread
keyword must immediately follow the static
or extern
keyword, if either of these is specified in the variable’s
declaration.
- The declaration of a thread-local variable can include an initializer, in the same manner as a normal global or static variable
declaration.
- The C address (&) operator can be used to obtain the address of a thread-local variable.
我想知道关键字必须在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] = '[=11=]'; /* 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);
}
重读你引用的文字(强调我的):
- The __thread keyword must immediately follow the static or extern keyword, if either of these is specified in the variable’s declaration.
因此,如果两者均未指定,则此条款不适用。
至于"why",如果这个说法是正确的(我怀疑它大致是正确的但表述不准确),那只是"GNU C"的语法问题,其中__thread
从。您可以在 C11 标准中查找等效 _Thread_local
的语法要求。
线程局部变量的标准 C 存储 class 说明符是 _Thread_local
. The standard also says in §6.11 Future directions:
6.11.5 Storage class specifiers
The placement of a storage-class specifier other than at the beginning of the declaration
specifiers in a declaration is an obsolescent feature.
因此,标准说存储 class 关键字(static
、extern
、auto
— 不要使用它! — register
—同上 — _Thread_local
和 typedef
) 应该 出现在声明的开头。在出现 static
或 extern
和 _Thread_local
的情况下,书中的建议是 static
或 extern
应该放在第一位,而 _Thread_local
第二位。
当然,本书使用的是 __thread
而不是 _Thread_local
。这是一个特定于编译器(实现)的关键字,其行为类似于标准 C _Thread_local
和 Microsoft 的 __declspec(thread)
.
关于 thread local storage 文档的 GCC 文档(强调已添加):
At the user level, the extension is visible with a new storage class keyword: __thread
. For example:
__thread int i;
extern __thread struct state s;
static __thread char *p;
The __thread
specifier may be used alone, with the extern
or static
specifiers, but with no other storage class specifier. When used with extern
or static
, __thread
must appear immediately after the other storage class specifier.
The __thread
specifier may be applied to any global, file-scoped static, function-scoped static, or static data member of a class. It may not be applied to block-scoped automatic or non-static data member.
因此,您看到的是 GCC 特定于线程本地存储的表示法,正如我所指出的和 GCC 手册所指出的那样,存储 class 信息应该在声明中排在第一位(并且GCC 在 static
或 extern
之后明确表示 __thread
。
我正在阅读 Kerrisk's book 并看到以下内容作为 31-4 的注释,
- The
__thread
keyword must immediately follow thestatic
orextern
keyword, if either of these is specified in the variable’s declaration.- The declaration of a thread-local variable can include an initializer, in the same manner as a normal global or static variable declaration.
- The C address (&) operator can be used to obtain the address of a thread-local variable.
我想知道关键字必须在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] = '[=11=]'; /* 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);
}
重读你引用的文字(强调我的):
- The __thread keyword must immediately follow the static or extern keyword, if either of these is specified in the variable’s declaration.
因此,如果两者均未指定,则此条款不适用。
至于"why",如果这个说法是正确的(我怀疑它大致是正确的但表述不准确),那只是"GNU C"的语法问题,其中__thread
从。您可以在 C11 标准中查找等效 _Thread_local
的语法要求。
线程局部变量的标准 C 存储 class 说明符是 _Thread_local
. The standard also says in §6.11 Future directions:
6.11.5 Storage class specifiers
The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.
因此,标准说存储 class 关键字(static
、extern
、auto
— 不要使用它! — register
—同上 — _Thread_local
和 typedef
) 应该 出现在声明的开头。在出现 static
或 extern
和 _Thread_local
的情况下,书中的建议是 static
或 extern
应该放在第一位,而 _Thread_local
第二位。
当然,本书使用的是 __thread
而不是 _Thread_local
。这是一个特定于编译器(实现)的关键字,其行为类似于标准 C _Thread_local
和 Microsoft 的 __declspec(thread)
.
关于 thread local storage 文档的 GCC 文档(强调已添加):
At the user level, the extension is visible with a new storage class keyword:
__thread
. For example:__thread int i; extern __thread struct state s; static __thread char *p;
The
__thread
specifier may be used alone, with theextern
orstatic
specifiers, but with no other storage class specifier. When used withextern
orstatic
,__thread
must appear immediately after the other storage class specifier.The
__thread
specifier may be applied to any global, file-scoped static, function-scoped static, or static data member of a class. It may not be applied to block-scoped automatic or non-static data member.
因此,您看到的是 GCC 特定于线程本地存储的表示法,正如我所指出的和 GCC 手册所指出的那样,存储 class 信息应该在声明中排在第一位(并且GCC 在 static
或 extern
之后明确表示 __thread
。