文章目录
- pthread_equal()
- 线程参数传递
- 传递指针
- 传递整型参数
- 方式一:直接强制转换
- 方式2:使用 intptr_t / uintptr_t(C99标准推荐)
- 方式3:为单个整数动态分配内存
- 传递复杂数据
- 方式1:定义结构体
- 方式2:为每个线程动态分配独立结构
- 传参选择依据
pthread_equal()
- POSIX标准只定义了线程相关数据类型的接口行为,没有规定其内部实现。在不同的操作系统或架构上:
- pthread_t 可能是:unsigned long(Linux x86_64)、结构体指针(某些BSD系统)、整数索引等
- 互斥锁、条件变量等可能有不同的内部布局
- pthread_equal() 是 Pthreads 标准中专门用于比较两个线程 ID(pthread_t 类型)是否相等的函数,解决了 pthread_t 类型跨平台兼容性问题(避免直接用 == 比较的风险)
- “不透明”的数据类型:
| 数据类型 | 描述 |
|---|
| pthread_t | 线程 ID |
| pthread_mutex_t | 互斥对象(mutex) |
| pthread_mutexattr_t | 互斥属性对象 |
| pthread_cond_t | 条件变量(condition variable) |
| pthread_condattr_t | 条件变量的属性对象 |
| pthread_key_t | 线程特有数据的键(Key) |
| pthread_once_t | 一次性初始化控制上下文(control context) |
| pthread_attr_t | 线程的属性对象 |
函数原型
#include<pthread.h>intpthread_equal(pthread_tt1,pthread_tt2);
参数
- 要比较的线程 ID,如
pthread_self()返回值、pthread_create输出的 ID
返回值
- 非 0 值:t1 和 t2 指向同一个线程
- 0:两个线程 ID 不相等
// 错误:不可移植if(tid1==tid2){...}// 正确:可移植if(pthread_equal(tid1,tid2)!=0){...}// 检查当前线程是否是特定线程if(pthread_equal(pthread_self(),main_thread_id)!=0){// 这是主线程}
线程参数传递
- 线程参数传递主要涉及两种方式:
- 传递指针:传递变量的地址(或字符串常量地址)
- 传递整数值:将整数值直接转换为指针传递
传递指针
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>void*func(void*arg){char*str=(char*)arg;printf("%s\n",str);pthread_exit(NULL);}intmain(intargc,constchar*argv[]){pthread_ttid;char*str="Hello Thread!";intret=pthread_create(&tid,NULL,func,str);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}ret=pthread_join(tid,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}return0;}
优点
- 可以传递任意复杂的数据结构
- 传递效率高(只传指针,不拷贝数据)
- 符合 void* 指针的设计初衷
注意事项
数据生命周期管理
// 危险:传递局部变量的地址voidcreate_thread(){charbuffer[64];// 栈上分配sprintf(buffer,"Thread data");pthread_create(&tid,NULL,func,buffer);// 函数返回时buffer被释放,但线程可能还在访问!}// <- 这里buffer的栈内存被回收!// 安全做法1:传递全局/静态变量staticcharbuffer[64];// 或全局变量voidcreate_thread(){sprintf(buffer,"Thread data");pthread_create(&tid,NULL,func,buffer);}// 安全做法2:动态分配voidcreate_thread(){char*buffer=malloc(64);sprintf(buffer,"Thread data");pthread_create(&tid,NULL,func,buffer);// 在线程函数中必须free!}// 安全做法3:传递字符串常量(只读段)pthread_create(&tid,NULL,func,"Constant string");
多线程并发访问
// 危险:多个线程共享同一数据指针intshared_data=0;for(inti=0;i<5;i++){// 所有线程都收到 &shared_data 的指针pthread_create(&tids[i],NULL,func,&shared_data);}// 线程间会竞争修改shared_data,需要同步机制!
传递整型参数
方式一:直接强制转换
#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>void*func(void*arg){printf("arg:%d\n",(int)arg);pthread_exit(NULL);}intmain(intargc,constchar*argv[]){pthread_ttid;inta=10;intret=pthread_create(&tid,NULL,func,a);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}ret=pthread_join(tid,NULL);if(ret!=0){errno=ret;perror("pthread_create");exit(EXIT_FAILURE);}return0;}
- 可以工作但是编译会报警告:
- 可移植性问题:如果int和指针大小不同(如int是32位,指针是64位),转换可能丢失精度
- 类型安全问题:绕过了类型系统,编译器无法检查
- 标准未定义:C标准不保证这种转换的行为
- 严格说来,对于
int与void*之间相互强制转换的后果,C语言标准并未加以定义。不过,大部分C语言编译器允许这样的操作,并且也能达成预期的目的
方式2:使用 intptr_t / uintptr_t(C99标准推荐)
#include<stdint.h>// 包含intptr_t的定义// 传递inta=10;pthread_create(&tid,NULL,func,(void*)(intptr_t)a);// 接收void*func(void*arg){intvalue=(int)(intptr_t)arg;// 先转intptr_t,再转int}
- C99标准定义的有符号整数类型intptr_t,保证可以安全地存储指针值(转换为整数再转回指针不变)
- 大小与指针相同,解决了可移植性问题
方式3:为单个整数动态分配内存
// 传递int*p=malloc(sizeof(int));*p=10;pthread_create(&tid,NULL,func,p);// 在线程函数中free(p)// 接收void*func(void*arg){intvalue=*(int*)arg;free(arg);// 得释放!// ...}
传递复杂数据
方式1:定义结构体
typedefstruct{intid;constchar*name;intpriority;void*device_handle;}ThreadParams;// 传递ThreadParams params={1,"SensorReader",10,dev_handle};pthread_create(&tid,NULL,sensor_thread,¶ms);// 注意:params必须是全局的或动态分配的// 如果params是局部变量,确保线程在函数返回前已使用完数据
方式2:为每个线程动态分配独立结构
for(inti=0;i<NUM_THREADS;i++){ThreadParams*params=malloc(sizeof(ThreadParams));params->id=i;params->name=thread_names[i];params->priority=priorities[i];pthread_create(&tids[i],NULL,worker_thread,params);// 在线程函数中free(params)}
传参选择依据
| 数据类型 | 推荐方法 | 代码示例 | 注意事项 |
|---|
| 字符串常量 | 直接传递 | pthread_create(..., "string") | 只读,安全 |
| 单个整数 | intptr_t转换 | (void*)(intptr_t)value | 可移植,简洁 |
| 单个指针 | 直接传递 | (void*)&data | 注意生命周期 |
| 多个参数 | 结构体指针 | (void*)¶ms | 结构体需全局或动态分配 |
| 大量数据 | 传递数据指针 | (void*)large_buffer | 考虑拷贝开销 vs 共享风险 |