线程概念
一个进程需要访的大部分资源,诸如自身的代码、数据、new\malloc的空间数据、命令行参数和环境变量、动态库、甚至是系统调用访问内核代码…都是通过虚拟地址空间来访问的。换而言之,进程地址空间是进程的资源窗口!!
进程创建费时费力。在创建时,我们需要为进程创建PCB、地址空间、页表、将进程自身的代码和数据换入内存并建立映射、将进程PCB状态改为R状态、添加带运行队列中… 但如果现在已经存在一个线程了,我仅仅将进程PCB复制多份,然后让所有“进程”PCB全部指向同一个虚拟地址空间。然后通过技术手段,将虚拟地址空间合理分配给每一个“进程”。当CPU调度执行该“”进程“时,只会执行原本进程中的一部分代码和数据,执行我们要执行任务的一部分任务,我们将这种比传统“进程”更加轻量化的进程就称为线程!!
主线程和子线程
共享:
.text
.bss
.data
堆
动态加载区
环境变量
命令行参数
-通信:全局变量,堆
不共享
一共五个线程,栈区被平均分成五块
在Linux下: 线程就是进程-轻量级进程
对于内核来货,线程就是进程
多进程和多线程的区别:
多进程: 始终共享的资源 代码、文件描述符、内存映射区--mmap
多线程:始终共享的资源:堆、全局变量,节省资源
查看指定线程的LWP号:
线程号和线程ID是有区别的
线程号是给内核看的
查看方式
找到程序的进程ID
ps -Lf pid
线程的创建

#include <stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void * myfunc(void *arg)
{printf("child pthread id : %ld\n",pthread_self());
}
int main()
{pthread_t pthid;int ret;ret=pthread_create(&pthid,NULL,myfunc,NULL);if(ret!=0){printf("error number is %d\n",ret);printf("%s\n",strerror(ret));}printf("parent pthread id : %ld\n",pthread_self());for(int i=0;i<5;i++){printf("i=%d\n",i);}sleep(2);return 0;
}
使用sleep()函数先防止主函数1进程结束,导致子进程消失
单个线程退出 --pthread_exit
#include <stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void * myfunc(void *arg)
{printf("child pthread id : %ld\n",pthread_self());exit(0);
}
int main()
{pthread_t pthid;int ret;int i=0;ret=pthread_create(&pthid,NULL,myfunc,NULL);if(ret!=0){printf("error number is %d\n",ret);printf("%s\n",strerror(ret));}printf("parent pthread id : %ld\n",pthread_self());while(i<10){printf("i=%d\n",i);i++;}pthread_exit(NULL);sleep(2);return 0;
}
阻塞等待线程退出,获取线程退出状态--pthread_join

#include <stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int num=100;
void * myfunc(void *arg)
{printf("child pthread id : %ld\n",pthread_self());
// exit(0);for(int i=0;i<5;i++){printf("child pthread %d\n",i);}pthread_exit(&num);
}
int main()
{pthread_t pthid;int ret;int i=0;ret=pthread_create(&pthid,NULL,myfunc,NULL);if(ret!=0){printf("error number is %d\n",ret);printf("%s\n",strerror(ret));}printf("parent pthread id : %ld\n",pthread_self());void*ptr=NULL;pthread_join(pthid,&ptr);printf("num=%d\n",*(int*)ptr);while(i<10){printf("i=%d\n",i);i++;}sleep(2);return 0;
}
线程分离--pthread_detach
杀死(取消)线程--pthread_cancel
比较两个线程ID是否相等(预留函数) --pthread_equal
线程的分离属性
1.分离属性是属于线程的属性,有了分离属性的线程,是不需要别的线程去接合自己的(回收自己的资源)。
但是虽然是分离的,但是如果进程退出,该线程还是会退出的。
2.分离属性的特点
该线程的资源,不需要被别的线程回收(接合),资源是由系统来回收的。
分离属性 --> 不需要被的线程去调用pthread_join()来回收资源。
非分离属性 --> 需要被别的线程去调用pthread_join来回收资源。
通过属性设置线程的分离
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);
#include <stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void * myfunc(void *arg)
{printf("child pthread id : %ld\n",pthread_self());
}
int main()
{pthread_t pthid;int ret;pthread_attr_t arr;pthread_attr_init(&arr);pthread_attr_setdetachstate(&arr,PTHREAD_CREATE_DETACHED);ret=pthread_create(&pthid,&arr,myfunc,NULL);if(ret!=0){printf("error number is %d\n",ret);printf("%s\n",strerror(ret));}printf("parent pthread id : %ld\n",pthread_self());for(int i=0;i<5;i++){printf("i=%d\n",i);}sleep(2);pthread_attr_destroy(&arr);return 0;
}