非常重要
线程的概念:
-
先说进程:传统操作xi'to系统中使用pcb来描写一个程序的运行 ----> pcb就是进程
-
linux下的pcb用来模拟实现线程,因此linux下的pcb实际就是一个轻量级的LWP 线程 LWP(light weight process)
-
这个轻量级进程因为共同大部分进程资源;相较与传统进程更加轻量化
进程是资源分配的基本单位-- 因为程序运行时资源是分配给整个线程组的
线程是cpu调度的基本单位 -- 因为线程是很多轻量级进程的集合,同时资源是一个进程资源量
线程之间资源的独有与共享
独有:栈 寄存器(上下文信息) 信号屏蔽字 errno[全局变量] 线程ID 调度优先级 | 在虚拟地址空间中每个小线程都有自己的栈 |
共享:虚拟地址空间 (数据段 共享 代码段) 文件描述符表(他和虚拟地址空间不是一个结构体) 共享文件描述符 当前工作路径, 信号处理方式 |
|
多任务的执行:既可以使用多进程也可以使用多线程 ,哪一个好 分析他们的优缺点 看使用场景定
多线程任务处理的优点:
多线程共用进程的大部分资源
1、线程间通信处理进程间的方式
2、创建/销毁一个线程的成本更低
3、线程间的调度相较于进程要求更低
多线程的缺点:
线程之间缺乏访问控制,有些系统调用/异常针对的是整个进程;稳定性相对与进程更低
使用场景:
shell 就是用的是多进程(让子进程运行命令,以保证shell 的正常的运行),对主程序安全性很高的程序,需要使用都进程
线程查看:(shell中)
ps -efLl|head -n 1 && ps -feL|grep creat -L就是查看线程信息 -l查看详细信息
线程控制:线程创建、线程终止、线程等待、线程分离
linux下操作系统并没有提供线程的控制的系统调用接口
因此大佬们封装了一套线程控制接口库(动态库或者静态库)
使用库函数创建的线程--------用户态线程 这个用户态形成在内核中使用一个轻量级进程实现调度
linux下的线程:用户态线程 + 轻量级进程
线程创建:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
thread:用于获取线程ID 【地址】 线程地址空间在整个虚拟地址空间中首地址
attr:设置线程属性---》一般置空NULL
start_routine:线程的入口函数
arg:传递给线程函数的实参
返回值:成功的是0,失败是!0,erron错误编号
ps -efL -L查看线程
线程中的id讨论:
tid | 线程地址空间首地址 本质:是一个地址 |
pcb->pid | 轻量级进程id |
pdb->tgid | 进程(线程组)id,默认等于首线程id |
线程终止:3个
1、return 不能在main()函数中return,在main中return就会退出进程,这样就会导致所有的线程退出
2、pthread_exit(void*reval); 退出线程 谁调用谁退出 pthread_self() 获取调用线程的tid
reval就是返回值
3、pthread_cancel(pthread_thread_t thread); 取消其他线程,让其他线程退出
thread是取消的线程
线程的终止都可以对主线程进行操作,进程不会终止
线程等待:pthread_join
等待线程退出,获取线程推出的结果。释放退出线程的资源;
一个线程创建出来,默认有一个属性joinable;处于joinbale属性的线程退出后,不会自动释放资源;需要被其他线程等待才能释放资源;
不等待,就会资源泄露。
int pthread_join(pthread_t thread, void **retval); 功能:阻塞等待指定线程退出;
通过retval获取返回值
线程等待:pthread_join
等待线程退出,获取线程推出的结果。释放退出线程的资源;
一个线程创建出来,默认有一个属性joinable;处于joinbale属性的线程退出后,不会自动释放资源;需要被其他线程等待才能释放资源;
不等待,就会资源泄露。
int pthread_join(pthread_t thread, void **retval); 功能:阻塞等待指定线程退出;
通过retval获取返回值
定义一个变量
char ptr[ ] = ''nihaoa '';开辟了空间,
char* ptr = "nihaoa ";没有开辟空间,不存在被销毁
pthread_exit(ptr); 只有char* ptr能被接收到
1 #include <pthread.h>
2 #include <unistd.h>
3 #include <stdio.h>
4
5 void* child(void* arg){
6 while(1){
7 printf("this is a child_thread ---2--- %s\n",(char*)arg);
8 sleep(1);
9 char ptr[] = "nihao a !!";// 这里的ptr就是buff,就是定义一个ptr[],然后把常量复制 到ptr[]
W> 10 char* ptr1 = "nihao a !!";// 而char* ptr1是定义一个指针,把常量地址复制到buff中
E> 11 pthread_exit("this is a exit_child_code \n");
12 pthread_exit(ptr);// ??
13 pthread_exit(ptr1);// ??
14 }
15 return NULL;
16 }
17
18 int main (){
19 pthread_t tid;
20 // int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
21 // void *(*start_routine) (void *), void *arg);
W> 22 char *arg = "this is a thrad_rutine";
23 int ret = pthread_create(&tid, NULL, child, (void*)arg);
23
24 if (ret != 0 ){
25 printf("threadRoutine create error!!!");
26 return -1 ;
27 }
28 printf("tid is %lu",tid);
29
30 void* retval ;
31 pthread_join(tid, &retval);
32 while(1){
33 printf("this is a primary pthreadRutine\n");
34 sleep(1);
35 printf("child 1 :exit info:%s\n", retval);
36 }
37 return 0;
38 }
pthread_join(tid, &receive);
线程分离
是将线程joinable属性修改成detach属性
线程是detach属性,线程退出后自动回收资源---- 不需要被等待 没有返回值(返回值的空间已经被释放pthread_detach())
int pthread_detach(pthread_t thread);
试用的场景:不需要返回值的
只需要知道线程的id,在任何位置,都可以进行线程分离----设置属性为detach属性