__thread详解(gcc关键字)

本文介绍了线程局部存储(TLS)机制,通过该机制分配的变量每个线程有独立实例。着重阐述了GCC内置的__thread线程局部存储设施,其存储效率高,各线程值互不干扰,但存在限制,如只能修饰POD类型,对变量定义和使用场景也有要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Thread Local Storage
线程局部存储(tls)是一种机制,通过这一机制分配的变量,每个当前线程有一个该变量的实例.

// 释义
__thread是GCC内置的线程局部存储设施,其存储效率可以和全局变量相比;
__thread变量在每一个线程中都有一份独立实例,各线程值是互不干扰的。
可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。

// 自身的限制
只能修饰POD类型(类似整型指针的标量,不带自定义的构造、拷贝、赋值、析构的类型,二进制内容可以任意复制memset,memcpy,且内容可以复原)。
不能修饰class类型,因为无法自动调用构造和析构函数。
可用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或class的普通成员变量。且__thread变量值只能初始化为编译器常量
__thread限定符(specifier)可以单独使用,也可带有extern或static限定符,但不能带有其它存储类型的限定符。
__thread可用于全局的静态文件作用域,静态函数作用域或一个类中的静态数据成员。不能用于块作用域,自动或非静态数据成员。

// 变量定义

__thread int i;
extern __thread struct state s;
static __thread char *p;

// 例子 1

#include <iostream>
#include <pthread.h>
using namespace std;
 
//一个用__thread关键字修饰的全局变量
__thread int g_iThreadCount = 0;
 
void *pthreadFunc1(void *pArg)
{
	g_iThreadCount += 1;
	cout << "pthreadFunc1::g_iThreadCount = " << g_iThreadCount << endl;
	pthread_exit((void *)1);
1
 
void *pthreadFunc2(void *pArg)
{
	g_iThreadCount += 2;
	cout << "pthreadFunc2::g_iThreadCount = " << g_iThreadCount << endl;
	pthread_exit((void *)2);
}
 
int main(void)
{
	int iRet;
	pthread_t pthreadId1;
	pthread_t pthreadId2;
	
	pthread_create(&pthreadId1, NULL, pthreadFunc1, NULL);
	pthread_create(&pthreadId2, NULL, pthreadFunc2, NULL);
	
	pthread_join(pthreadId1, NULL);
	pthread_join(pthreadId2, NULL);
	
	return 0;
}

pthreadFunc1::g_iThreadCount = 1
pthreadFunc2::g_iThreadCount = 2

// 例子 2

#include <iostream>  
#include <pthread.h>  
#include <unistd.h>
	
using namespace std; 

const int i=5;  
__thread int var=i;//两种方式效果一样  

static __thread int var2 = 15;//  

static void* worker1(void* arg);  
static void* worker2(void* arg);  

int main(){  
    pthread_t pid1,pid2;  

    static __thread  int temp=10;//修饰函数内的static变量  

    pthread_create(&pid1,NULL,worker1,NULL);  
    pthread_create(&pid2,NULL,worker2,NULL);  
    pthread_join(pid1,NULL);  
    pthread_join(pid2,NULL);  

    cout<<"main var addr :" << &var<<endl;     // 0x7f73a30f0734
    cout<<"main var2 addr :" << &var2<<endl;   // 0x7f73a30f0738
    cout<<temp<<endl;                          //输出10   
    return 0;  
}  

static void* worker1(void* arg){  
    cout<<"worker1 var :" << ++var<<endl;        // 6  
    cout<<"worker1 var addr :" << &var<<endl;    // 0x7f73a20f86f4
    cout<<"worker1 var2 :" << ++var2<<endl;      // 16
    cout<<"worker1 var2 addr :" << &var2<<endl;  // 0x7f73a20f86f8
}  

static void* worker2(void* arg){  
    sleep(1);//等待线程1改变var值,验证是否影响线程2  
    cout<< "worker2 var :" << --var<<endl;       // 4
    cout<<"worker2 var addr :" << &var<<endl;    // 0x7f73a18f76f4
    cout<<"worker2 var2 :" << --var2<<endl;      // 14
    cout<<"worker2 var2 addr :" << &var2<<endl;  // 0x7f73a18f76f8
}

[james_xie@james-desk myCode]$ g++ threadvar.c -o threadvar -lpthread
[james_xie@james-desk myCode]$ ./threadvar 
<think>嗯,用户让我解释一下pthread_create函数的声明,这个函数是用来创建线程的。首先,我需要回忆一下POSIX线程的相关知识。pthread_create是POSIX线程库中的一个重要函数,用于创建新的线程。它的参数看起来有点复杂,我得逐一分析每个参数的作用和类型。 首先看函数原型:extern int pthread_create (pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), void *__restrict __arg)。这里可能需要解释每个参数的含义,比如第一个参数是指向pthread_t的指针,用来保存新线程的ID。第二个参数是线程属性,通常可以设为NULL使用默认属性。第三个是线程函数的指针,这个函数接受void*参数并返回void*。第四个是传递给线程函数的参数。 接下来,用户可能想知道如何使用这个函数,比如具体的代码示例。可能需要提供一个简单的例子,说明如何定义线程函数,如何传递参数,以及如何编译链接,因为pthread库需要-lpthread选项。 另外,需要注意线程的错误处理,pthread_create返回0表示成功,非0表示错误,所以检查返回值很重要。还有线程的属性,如果用户不设置,用NULL就行,但如果有特殊需求,比如设置分离状态或栈大小,就需要使用pthread_attr_t相关函数。 用户可能对__restrict和__THROWNL这些修饰符不太熟悉,可能需要解释一下,比如__restrict是C99的关键字,表示指针是唯一访问该数据的途径,帮助编译器优化。__THROWNL可能表示函数不会抛出异常,但在C中异常处理不常见,可能更多是宏定义。 另外,线程安全方面,如果多个线程同时创建,需要注意传入的参数是否安全,比如arg参数如果多个线程共享,可能需要同步机制。还有线程函数的返回值,如何通过pthread_join获取。 可能还需要提醒用户,线程创建后,主线程需要决定是等待子线程结束(使用pthread_join)还是分离线程(使用pthread_detach),否则可能导致资源泄漏。 最后,编译时的链接选项需要加上-pthread或-lpthread,不同的编译器可能有不同的要求,需要指出常见的编译命令格式。 总结一下,回答需要分步骤,先介绍函数的作用,参数详解,返回值,使用示例,注意事项,常见错误和编译方法。确保结构清晰,帮助用户逐步理解如何使用这个函数。</think>以下是关于`pthread_create`函数的详细解析: --- ### **函数功能** `pthread_create`是POSIX线程库(pthread)中用于**创建新线程**的核心函数。新线程会与调用线程并发执行。 --- ### **函数声明** ```c extern int pthread_create( pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine)(void *), void *__restrict __arg ) __THROWNL __nonnull((1, 3)); ``` --- ### **参数详解** 1. **`pthread_t *__restrict __newthread`** - **作用**:输出参数,用于存储新线程的标识符(线程ID)。 - **注意**:必须指向有效的内存地址,线程ID由系统分配。 2. **`const pthread_attr_t *__restrict __attr`** - **作用**:设置线程属性(如栈大小、调度策略等)。 - **默认行为**:若为`NULL`,则使用默认属性。 - **高级用法**:可通过`pthread_attr_init`自定义属性。 3. **`void *(*__start_routine)(void *)`** - **作用**:新线程的入口函数指针。 - **函数签名**:必须接受一个`void *`参数并返回`void *`。 - **示例**: ```c void *thread_function(void *arg) { // 线程逻辑 return NULL; } ``` 4. **`void *__restrict __arg`** - **作用**:传递给`__start_routine`的参数。 - **技巧**:可通过结构体传递多个参数。 --- ### **返回值** - **成功**:返回`0`。 - **失败**:返回错误码(非零值),可通过`errno`或`strerror`解析。 --- ### **使用示例** ```c #include <pthread.h> #include <stdio.h> void *print_message(void *msg) { printf("Message: %s\n", (char *)msg); return NULL; } int main() { pthread_t tid; char *message = "Hello from thread!"; // 创建线程 int ret = pthread_create(&tid, NULL, print_message, message); if (ret != 0) { perror("Thread creation failed"); return 1; } // 等待线程结束 pthread_join(tid, NULL); return 0; } ``` --- ### **注意事项** 1. **线程生命周期** - 新线程与调用线程独立运行,主线程退出可能导致子线程终止。 - 使用`pthread_join`等待线程结束,或`pthread_detach`分离线程。 2. **参数传递安全** - 确保`__arg`指向的数据在线程运行期间有效(避免传递栈变量后立即释放)。 3. **资源管理** - 线程结束后需释放其资源(如动态分配的内存)。 4. **编译选项** - 编译时需链接`pthread`库: ```bash gcc program.c -o program -lpthread ``` --- ### **错误处理** 常见错误码: - `EAGAIN`:资源不足(如线程数超出限制)。 - `EINVAL`:无效的线程属性。 - `EPERM`:权限不足。 --- 通过以上步骤,您可以安全地使用`pthread_create`实现多线程编程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值