操作系统没有直接给用户提供线程的系统调用函数 , 所有就要大佬将一套线程控制接口封装成了库函数共用户使用所以创建的线程是一个用户态的线程, 但是在内核中对应有一个轻量级进程实现程序的调度运行
线程创建
int pthread_create(pthread_t *thread, const pthread_attr_t *attr
void *(*start_routine) (void *), void *arg);
线程的创建是通过pthread_create()函数来完成的. 头文件是pthread.h 其中一共有四个参数
- thread
是一个无符号整形的数据 , 它用来接收创建的线程的标识符 - attr
用来设置线程的属性, 一般置位NULL , 表示使用默认属性 - void *(*start_routine) (void *)
是一个函数指针, 传入的函数为创建线程的执行函数 - arg
是一个参数 , 表示传入执行函数的参数 - 返回值: 创建线程成功则返回 0
//线程执行函数
void* fun(void* arg){
while(1){
printf("----------新线程--------- %s \n",arg);
sleep(1);
}
return NULL;
}
int main(){
//用来接收pthread_create的返回值, 判断线程是否创建成功
int ret;
//tid用来接收创建线程的ID
pthread_t tid;
//作为参数传入线程执行函数
char* str="houxinggang";
ret = pthread_create(&tid,NULL,fun,(void*)str);
if(ret!=0){
printf("创建线程失败!!\n");
return -1;
}
while(1){
printf("----------主线程--------- \n");
sleep(1);
}
return 0;
}
执行代码后,可以看到主线程与新线程都在运行
进程ID与线程ID
线程终止
- return : 在主线程中return, 退出进程 在普通线程中return退出的是调用线程
- pthread_exit(void ** ratval) : 退出调用的线程(包含主线程)
主线程退出,进程不会退出, 所有的线程推出,则进程退出 retval通常置空 - pthread_cancel (pthread_t tid) : 取消指定的现线程 (线程退出也会形成僵尸线程,多以线程也要等待)
以上书代码为例
void* fun(void* arg){
int i=0;
while(1){
printf("----------新线程--------- %s \n",arg);
i++;
if(i==8)
pthread_exit(NULL);
sleep(1);
}
return NULL;
}
int main(){
//用来接收pthread_create的返回值, 判断线程是否创建成功
int ret;
//tid用来接收创建线程的ID
pthread_t tid;
//作为参数传入线程执行函数
char* str="houxinggang";
ret = pthread_create(&tid,NULL,fun,(void*)str);
if(ret!=0){
printf("创建线程失败!!\n");
return -1;
}
while(1){
printf("----------主线程--------- \n");
sleep(1);
}
return 0;
}
创建线程在执行8秒之后退出
进程等待
线程需要被等待是有前提的 : 这个线程处于一个joinable属性, 一个线程被创建,有一个joinable属性, 这个属性的线程退出后不会自动回收资源,需要被等待
int pthread_join(pthread_t tid, void *retval); : tid:等待指定的线程ID retval用来接收退出返回值 此函实际上是一个阻塞函数, 当指定的线程没有退出时, 它将一直等待
*
注意 : 这里用于接受返回信息的retval是一个 void 类型的二级指针当我们按照如下的代码进行编写是会出现错误
//1.当给指针置空时
void** retval=NULL;
//2.当二级指针指向也指针时
void **retval;
pthread_join(tid,(char*)*retval);
如上图所示 char** 类型的 b 指针中存放的是一片 char类型空间的地址 , 而字符串的首地址将存放在 char 类型的的空间中 当我们给二级指针指向空时, 他里面存放的是非法的一块地址,当二级指针指向野地址时, 也是错误的 .
回去线程退出的返回值程序
void* str_statr(void* arg){
char* buf="nuhao";
sellp(5);
return buf;
}
int main(){
pthread_t pid;
int ret=pthread_creat(&tid, NULL,str_statr,NULL);
if(ret!=0){
printf("线程创建失败!!\n");
return -1;
}
void* retval;
pthread_join(tid,&retval);
printf("线程退出的原因:%s",(char*)retval);
return 0;
}
进程分离
分离一个线程, 就是设置线程的属性, 将线程的joinable属性修改为detach属性, 处于这个属性的线程,退出之后将自动回收资源, 并且因为资源已经被自动释放,所以不能被等待, 否则报错;
pthread_detach(tid)
线程分离可以在任意线程任意时间分离, 包括分离自己;
分离一个线程的使用场景,用户根本不关心线程的处理结果