守护进程和线程
学习目标说出守护进程的特点独立完成守护进程的创建独立实现多个线程的创建独立实现线程的退出和资源回收理解线程同步的思想1、守护进程定义又称为精灵进程、是Linux中后台服务进程通常独立于控制终端并且周期性的完成某种任务或者等待处理某些发生事件。例子linux后台的一些系统服务进程没有控制终端不能直接和用户交互。不受用户登录、注销的影响一直在运行着都是守护进程。引申知识点凡是依赖于终端的进程都可以使用ctrl c杀死。2、守护进程的特点Linux后台服务进程独立于控制终端周期性的执行某种任务不受用户登录、注销的影响一般采用的d结尾的名字3、进程组和会话概念进程组是一个或者多个进程的集合每个进程都属于一个进程组。进程组ID 第一个进程的ID(组长进程)。引申知识点ps -ef | wc -l -------------统计当前系统中总共有多少个进程行数kill -SIGKILL -进程组ID(负的)------------杀死进程组的所有进程会话一个或者多个进程组的集合。创建会话的进程不能是进程组组长。需要有root权限新创建的会话会丢弃原有的控制终端建立新会话的时候先调用fork然后终止父进程最后子进程调用setsid函数创建会话。只要是创建了会话这个进程就脱离了控制终端的影响。引申知识点可以使用ps ajx来查看进程组ID和会话ID4、会话进程的创建1、fork子进程父进程退出目的子进程肯定不是组长进程2、子进程调用setsid函数创建会话该进程成了该会话的会长也成为了改组的组长不再受控制终端影响。3、改变当前进程的工作目录chdir(非必须)chdir(路径);4、重设文件掩码(非必须)umask(0000)目的为了增加子进程程序操作的灵活性不再受父进程文件掩码的影响。掩码作用用来决定新建文件或者文件夹最终的权限大小。查看当前xshell目录下所有进程的资源限制命令ulimit -a5、关闭文件描述符(非必须)close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);6、执行核心工作5.线程线程定义是轻量级的进程在Linux环境下线程的本质仍然是进程线程有PCB但没有独立的地址空间多个线程共享进程空间相当于合租进程拥有独立的地址空间有PCB相当于独居创建线程多了一个PCB两个PCB并不完全一致。从内核来看进程和线程都是一样的都有各自不同的PCB,只在用户层上进行区分。线程所有操作函数pthread_*是库函数而非系统调用。进程可以蜕变为线程引申知识点系统分配资源的最基本单位进程系统调度进程执行的最小单位线程多个子线程和主线程共享一个地址空间有一个PID通过线程编号来区分不同的线程栈不能共享栈大小8MB其余资源都可以共享主线程和子线程是谁先抢到CPU查看线程号ps -Lf PID同时也可以查看有几个线程线程共享资源文件描述符、每种信号的处理方式、当前工作目录、用户ID和组ID、内存地址空间(.text/.data/.bss/heap/共享库)线程非共享资源线程id、处理器现场和栈指针(内核栈)、独立的栈空间(用户空间栈)、errno变量、信号屏蔽字、调度优先级创建线程pthread_create函数功能创建线程头文件#include pthread.h函数原型int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine(void*),void *arg);函数返回值成功0失败-1函数参数pthread_t:传出参数保存系统为我们分配好的线程IDattr通常传NULL表示使用线程默认属性start_routine函数指针指向线程主函数(线程体)该函数运行结束则线程结束。线程执行函数。arg:线程主函数执行期间所使用的参数。注意点由于创建线程错误码不保存在error中因此不能直接用perror打印可以先用strerror把错误码换成错误信息打印如果任意一个线程调用了exit或_exit则整个进程的所有线程都终止主线程和子线程在同一个地址空间里pid相同主线程和子线程id不同。获取线程pid函数 pthread_self();无参数线程代码编译 gcc -o a.out 线程文件.c -lpthread6.线程的退出、回收、分离在线程中禁止使用exit函数会导致整个线程退出应该是有pthread_exit这个函数只会退出一个线程不会导致整个线程都退出。pthread_exit函数线程号LWP函数功能退出单个线程函数原型void pthread_exit(void *retval);函数参数retval表示线程退出状态通常传NULLretval必须是全局的或者是malloc申请分配的不能在线程函数的栈上分配否则当其他线程得到这个返回指针时线程函数已经退出栈空间会被回收。pthread_join函数获取线程的状态回收子线程为了避免僵尸线程的产生利用pthread_join函数函数功能阻塞等待线程退出获取线程的状态。对应进程中的waitpid()函数。函数原型int pthread_join(pthread_thread,void **retval)函数返回值成功0失败非0pthread_detach函数线程分离函数功能实现线程分离,让子线程与主线程断开关系。线程结束之后其退出状态不由其他线程获取而是直接自己主动释放。僵尸进程产生的原因由于进程死后大部分资源被释放一点残留资源仍存与系统中导致内核认为该进程任然存在。线程分离可以使用pthread_create函数参2(线程属性)来设置线程分离。也可以在创建线程之后调用pthread_datach函数。函数原型int pthread_detach(pthread_t thread);函数返回值成功0失败错误号函数参数要设置的分离属性的那个线程线程终止之后其终止状态一直保留到其他线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态这样的线程一旦终止就立刻回收它所占用的资源而不保留终止状态。pthread_join和pthread_datach函数不能共用。1. 定义线程属性 pthread_attr_t attr;2. 初始化属性 pthread_attr_init(attr);3. 设置分离属性修正函数名 传地址pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);//自动释放pthread_attr_setdetachstate(attr, PTHREAD_CREATE_JOINABLE);//必须使用pthread_join4. 创建线程把属性 attr 传进去pthread_t thread;int ret pthread_create(thread, attr, mythread7, NULL);7.取消线程取消线程函数int pthread_cancel(pthread_t pthread);函数返回值成功0失败错误号注意:线程的取消并不是实时的而有一定的延时需要等待线程达到某个取消点。引申知识点什么函数可以进入到内核系统调用函数或者阻塞函数查看取消点的系统调用列表命令man 7 pthreads设置取消点函数void pthread_testcancel(void);比较两个线程ID是否相等函数int pthread_equal(pthread_t t1,pthread_t t2);函数返回值如果两个相同返回非0值如果不同返回0