一、线程简介
一个单独的进程可以看做是一个线程。在创建线程之后,程序运行的地址空间没有发生变化,进程退出变成了线程,有主线程和子线程之分。创建出的主线程和子线程共用地址空间,有各自独立的PCB,子线程的PCB是从主线程中拷贝而来的。
主线程和子线程共享.text、.data、.bss、堆、环境变量、命令行参数、动态库加载区等,它们之间可通过堆、全局变量通信;
主线程和子线程不共享的是栈区,如果有多个线程,则栈区被平均分成了多份,各自独立。
多进程共享的是代码、文件描述符、内存映射区mmap等。相比于多进程,多线程可通过堆、全局变量通信,可节省系统资源。
二、线程相关
查看指定线程的LWP号:
先找到程序的进程ID:ps aux
再查看线程的LWP号:ps -Lf pid
三、相关函数
相同点:调用成功返回0,失败返回错误号
1.创建线程 -- pthread_create
函数原型:int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
参数:
thread:线程ID,无符号长整型
attr:线程属性,默认传NULL
start_routine:函数指针,传线程处理函数名字
arg:线程处理函数参数
循环创建线程
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <pthread.h> 4 #include <unistd.h> 5 6 void *myfunc(void *num) 7 { 8 // int i = *(int *)num; 9 int i = (int)num; 10 printf("%dth child thread id:%ld\n",i,pthread_self()); 11 return NULL; 12 } 13 14 int main() 15 { 16 int i; 17 pthread_t pthid[5]; 18 19 for(i=0;i<5;i++){ 20 //第四个参数,传地址的方式 21 // pthread_create(&pthid[i],NULL,myfunc,(void *)&i); 22 //传值的方式 23 int ret = pthread_create(&pthid[i],NULL,myfunc,(void *)i); 24 25 if(ret != 0){ 26 printf("error number:%d\n",ret); 27 //打印错误信息 28 printf("%s\n",strerror(ret)); 29 } 30 } 31 32 printf("parent thread id:%ld\n",pthread_self()); 33 34 for(i=0;i<5;i++){ 35 printf("i = %d\n",i); 36 } 37 38 sleep(2); 39 return 0; 40 }
2.单个线程退出 -- pthread_exit
函数原型:void pthread_exit(void *retval);
参数:retval:必须指向全局变量,否则无法传出
注意:如果有线程使用exit(),则会退出所有线程
1 #include <string.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <pthread.h> 5 #include <unistd.h> 6 7 void *myfunc(void *num) 8 { 9 printf("child thread id:%ld\n",pthread_self()); 10 for(int i=0;i<5;i++){ 11 printf("child i = %d\n",i); 12 if(i == 2){ 13 pthread_exit(NULL); 14 } 15 } 16 return NULL; 17 } 18 19 int main() 20 { 21 pthread_t pthid; 22 23 int ret = pthread_create(&pthid,NULL,myfunc,NULL); 24 25 if(ret != 0){ 26 printf("error number:%d\n",ret); 27 //打印错误信息 28 printf("%s\n",strerror(ret)); 29 } 30 31 32 printf("parent thread id:%ld\n",pthread_self()); 33 //主线程退出 34 pthread_exit(NULL); 35 36 for(int i=0;i<5;i++){ 37 printf("i = %d\n",i); 38 } 39 40 sleep(2); 41 return 0; 42 }
3.阻塞等待线程退出,获取线程退出状态 -- pthread_join
函数原型:int pthread_join(pthread_t thread,void **retval);
参数:
thread:要回收的子线程id
retval:读取线程退出时候携带的状态信息
void *ptr;
pthread_join(pthid,&ptr);
ptr指向的内存和子进程pthread_exit参数指向的内存为同一个
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 5 int number = 100; 6 7 void *myfunc(void *num) 8 { 9 printf("child thread id:%ld\n",pthread_self()); 10 for(int i=0;i<5;i++){ 11 printf("child i = %d\n",i); 12 if(i == 2){ 13 pthread_exit(&number); 14 } 15 } 16 return NULL; 17 } 18 19 int main() 20 { 21 pthread_t pthid; 22 23 int ret = pthread_create(&pthid,NULL,myfunc,NULL); 24 25 if(ret != 0){ 26 printf("error number:%d\n",ret); 27 //打印错误信息 28 printf("%s\n",strerror(ret)); 29 } 30 31 32 printf("parent thread id:%ld\n",pthread_self()); 33 34 void *ptr = NULL; 35 pthread_join(pthid,&ptr); 36 printf("number = %d\n",*(int *)ptr); 37 38 for(int i=0;i<5;i++){ 39 printf("i = %d\n",i); 40 } 41 42 sleep(2); 43 return 0; 44 }
4.线程分离 -- pthread_detch
函数原型:int pthread_detch(pthread_t thread);
调用该进程后主进程不需要使用pthread_join,子进程会自己回收自己的pcb
5.杀死(取消)进程 -- pthread_cancle
函数原型:int pthread_cancle(pthread_t thread);
注意:在要取消的子进程对应的处理函数内部,必须做过一次系统调用:write、read、printf等
6.比较两个线程id是否相等 -- pthread_equal
函数原型:int pthread_equal(pthread_t t1,pthread_t t2);
四、线程属性
1.线程属性类型:pthread_attr_t attr
2.线程属性操作函数
对线程属性初始化:int pthread_attr_init(pthread_attr_t *attr);
设置线程分离函数:int pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);
attr:线程属性
detachstate:PTHREAD_CREATE_DETACHED(分离)
PTHREAD_CREATE_JOINABLE(非分离)
释放线程资源函数:int pthread_attr_destroy(pthread_attr_t *attr);
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 5 void *myfunc(void *num) 6 { 7 printf("child thread id:%ld\n",pthread_self()); 8 for(int i=0;i<5;i++){ 9 printf("child i = %d\n",i); 10 } 11 return NULL; 12 } 13 14 int main() 15 { 16 pthread_t pthid; 17 18 //设置线程分离 19 pthread_attr_t attr; 20 //初始化行程状态 21 pthread_attr_init(&attr); 22 //设置线程分离属性 23 pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); 24 25 int ret = pthread_create(&pthid,&attr,myfunc,NULL); 26 27 if(ret != 0){ 28 printf("error number:%d\n",ret); 29 //打印错误信息 30 printf("%s\n",strerror(ret)); 31 } 32 33 34 printf("parent thread id:%ld\n",pthread_self()); 35 36 for(int i=0;i<5;i++){ 37 printf("i = %d\n",i); 38 } 39 40 sleep(2);
//释放线程资源 41 pthread_attr_destroy(&attr); 42 43 return 0; 44 }