线程标识和创建
线程标识
进程ID在整个系统中是唯一的,但线程ID只在它所属的进程环境中有效。
线程ID用pthread_t数据类型表示,所以可移植的操作系统实现不能把它作为整数来处理,因此必须使用函数来对两个线程ID进行比较
int pthread_equal(pthread_t tid1, pthread_t tid2);
//参数:两个线程的线程ID
//返回值:相等则返回非0值,否则返回0
线程也可以通过调用pthread_self函数获得自身线程ID
pthread_t pthread_self(void);
//返回值:调用线程的线程ID
当线程需要识别以线程ID作为标识的数据结构时,pthread_self函数可以与pthread_equal函数一起使用。
应用:比如:主线程可能把工作任务放在一个队列中,用线程ID来控制每个工作线程处理哪些作业,每个线程并不是任地处理从队列顶端取出的作业,每个工作线程只能移出标有自己线程ID的作业。
线程创建
可以使用pthread_create函数创建新线程。
int pthread_create(
pthread_t *thread, //返回线程ID
const pthread_attr_t *attr, //设置线程的属性,NULL为默认属性
void *(*start_routine)(void*), //县城启动后要执行的函数
void *arg); //传给线程启动函数的参数
//返回值:成功返回0,失败返回错误码
注意:
- pthread_create函数成功返回时,由thread指向的内存单元被设置为新创建线程的线程ID。
- 新创建的线程从start_routine函数的地址开始运行,该函数只有一个无类型指针arg,如果需要向start_routine函数传递的参数不止一个,那么需要把这些参数放到一个结构体中,然后把这个结构的地址作为arg参数传入。
- 线程创建时并不能保证哪个函数会先运行,不管是主线程还是新创建的线程。
pthread_create和pthread_self的用法:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void* route(void*){
printf("I am new thread...\n");
pthread_t tid = pthread_self(); //通过pthread_self获得线程tid
printf("my tid is %ld\n", tid);
return NULL;
}
int main(){
pthread_t tid;
int ret = pthread_create(&tid, NULL, route, NULL);
//新线程的线程ID在tid中,属性为NULL,要执行的函数为route,其函数参数为NULL;
if(ret != 0){
printf("create error...\n");
return 0;
}
sleep(1); //让主线程休眠一秒钟,sleep函数的头文件是unistd.h
return 0;
}
例子:
#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
void print(const char* s){ //打印调用该函数的线程的pid和tid
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
cout << s << " pid " << pid;
cout << " tid " << dec << tid << " "; //以十进制输出tid
cout << "(0x" << hex << tid << ")" << endl; //以十六进制输出tid
return NULL;
}
void* route(void* ){
print("new thread: ");
return NULL;
}
int main(){
int ret;
pthread_t tid;
ret = pthread_create(&tid, NULL, route, NULL);
if(ret != 0){
cout << "create error..." << endl;
}
print("main thread: ");
sleep(1);
return 0;
}
注意:
- 创建新线程后,要处理主线程和新线程的竞争关系。主线程需要休眠,如果主线程不休眠就有可能退出,这样可能新线程还没开始运行,整个进程就终止了。
- 获取线程ID时最好通过调用pthread_self函数获取,而不是从共享内存中读出或从线程的启动例程中以参数的形式读到。因为pthread_create函数会通过第一个参数thread返回新建线程的线程ID,但新建的线程并不能安全的使用,如果新线程在主线程调用pthread_create返回之前就运行了,那么新线程看到的是未经初始化的thread内容,这个并不是正确的线程ID。
- C++中cout << hex << n, cout << oct << n, cout << dec << n分别是将整数n以十六进制、八进制和十进制的形式输出。