后台运行的服务,和终端没有关系,终端关了还会跑 进程组:父进程和父进程创建的子进程构成一个组 会话: 注意事项: 1、调用进程不能是进程组组长,该进程变成新会话的首进程 2、该进程成为新进程组的组长 3、新会话放弃原来的控制终端,且没有新的控制终端 4、该调用进程如果是组长,则返回错误 5、只有当父进程死了,其中某一个子进程才可以调用setsid
创建会话: 创建子进程,父进程去死,子进程自当会长。
守护进程以d结尾 创建守护进程模型 * 1、创建子进程,父进程退出。所有工作在子进程中形式上脱离了控制终端 * 2、子进程当会长。在子进程中创建会话,setsid()使子进程完全独立出来脱离控制 * 3、切换工作目录$HOME,chdir()防止占用可拆卸文件系统 * 4、重置权限掩码umask()函数 * 5、关闭文件描述符012 * 6、执行守护进程核心逻辑 * 7、守护进程退出
创建一个守护进程:在$HOME/log/下创建一个文件:每分钟文件名+时间戳 E:\baiduwangpan\09系统课程\008(守护进程-线程)\3-视频
通过一个指令nohub,也可以达到守护进程的效果 nohub cmd >> log.txt & nohub cmd & //自己打印到hub.log文件中去了 * nohub会让cmd收不到SIGHUB信号 * &代表后台运行
车间:一个进程 一个线程大妈在炒菜,而你就是那个帮忙打酱油的线程,炒菜大妈不耽误炒菜
各自的栈和PCB,其他都共享, 默认情况一个进程只有一个线程 线程是最小的执行单位 进程是最小的资源分配单位 内核实现都是通过clone()函数实现的
线程共享资源: * 1、文件描述符表 * 2、每种信号的处理方式 * 3、当前工作目录 * 4、用户id和组id * 5、内存地址空间:.text/.data/.bss/heap/共享库 线程非共享资源 * 1、线程id * 2、处理器现场和栈指针(内核栈) * 3、独立栈空间(用户空间栈) * 4、errno变量 * 5、信号屏蔽字 * 6、调度优先级 线程优点: * 1、提高程序并发性 * 2、开销小 * 3、数据通信/共享数据方便 缺点: * 1、库函数、不稳定 * 2、调试、编写困难 * 3、对信号支持不好
参数 * 1、thread线程id,传出参数, * 2、attr线程属性 * 3、第3个参数:函数指针 (void*) func(void*),表明此线程执行什么东西 * 4、arg 线程执行函数的参数 返回值: * 成功返回0 * 失败返回errno
编译还要加上 gcc pthread_create.c -lpthread
#include <pthread.h> pthread_t pthread_self(void); Compile and link with -pthread.创建线程例子:
#include<unistd.h> #include<stdio.h> #include<pthread.h> void * thr(void *arg) { printf("I am a thread ! pid = %d,tid=%lu\n",getpid(),pthread_self()); return NULL; } int main() { pthread_t tid; pthread_create(&tid,NULL,thr,NULL); printf("I am a main thread,pid=%d,tid=%lu\n",getpid(),pthread_self()); sleep(1); return 0; } // ./a.out I am a main thread,pid=3145,tid=139957258413888 I am a thread ! pid = 3145,tid=139957249914624Eux系统课程)\08-linux-day08(守护进程-线程)\3-视频 第7个视频有关于make的使用
线程退出函数例子:
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> void* thr(void *arg) { printf("I am a thread,pid=%d,tid=%lu\n",getpid(),pthread_self()); //return NULL; // 这个退出时退出线程 pthread_exit(NULL); // 这个也是退出线程 //exit(1); // 这个是退出进程 } int main() { pthread_t tid; pthread_create(&tid,NULL,thr,NULL); printf("I am a main thread,pid=%d,tid=%lu\n",getpid(),pthread_self()); sleep(10); // 睡了10秒,让上面那一个线程执行完事看后边这一句能不能执行 printf("I will out!\n"); pthread_exit(NULL); return 0; }线程退出函数 pthread_exit 线程退出注意事项: * 1、在线程中使用pthread_exit * 2、在线程中使用return (主控线程return,代表退出进程) * 3、exit 代表退出整个进程
参数: thread 创建的时候传出的第一个参数 retval传出现成的退出信息 线程回收例子
#include<stdio.h> #include<unistd.h> #include<pthread.h> void * thr(void *arg) { printf("I am a thread,tid=%lu\n",pthread_self()); sleep(5); printf("I am a thread,tid=%lu\n",pthread_self()); return (void*)100; } int main() { pthread_t tid; pthread_create(&tid,NULL,thr,NULL); void *ret; pthread_join(tid,&ret); printf("ret exit with %d\n",(int)ret); pthread_exit(NULL); }线程回收函数也是阻塞等待
用这个函数杀死的会返回这个宏
#define PTHREAD_CANCELED ((void*) -1)代码执行的函数thr种需要有代码,为了有取消点,不然就得用另外一个函数设置取消点: void pthread_testcancel(void);
使用县城分离函数之后,就不用在使用pthread_join函数来回收资源了
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<string.h> void * thr(void * arg) { printf("I am a thread,self=%lu\n",pthread_self()); sleep(3); printf("I am a thread,self=%lu\n",pthread_self()); return NULL; } int main() { pthread_t tid; pthread_create(&tid,NULL,thr,NULL); sleep(4); pthread_detach(tid); // 分离线程 int ret=0; if((ret=pthread_join(tid,NULL))>0){ printf("join err:%d,%s\n",ret,strerror(ret)); } return 0; } ./03_detach I am a thread,self=140570218792704 I am a thread,self=140570218792704 join err:22,Invalid argument线程相等函数 pthread_equal(q1.q2); 线程id在进程内部是唯一的,在进程外部不一定唯一
#include<stdio.h> #include<unistd.h> #include<pthread.h> void *thr(void *arg) { int num=(int)arg; printf("I am %d thread,self=%lu\n",num,pthread_self()); return (void *)(100+num); } int main() { pthread_t tid[5]; int i; for(i=0;i<5;++i) { pthread_create(&tid[i],NULL,thr,(void*)i); } for(i=0;i<5;++i){ void *ret; pthread_join(tid[i],&ret); printf("i==%d,ret==%d\n",i,(int)ret); } return 0; } //编译: gcc -o 04_nthread 04_npthread -lpthread线程属性设置分离之后就不用再手动回收了 进程属性控制: 初始化线程属性 init pthread_attr_init(pthread_attr_t *attr); 销毁线程属性 int pthread_attr_destroy(pthread_attr_t * attr);
设置属性分离态 int pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate); * attr init 初始化的属性 * detachstate * PTRREAD_CREATE_DETACHED 线程分离 * PTHREAD_CREATE_JOINABLE允许回收
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<string.h> void * thr(void * arg) { printf("I am a thread,self=%lu\n",pthread_self()); return NULL; } int main() { pthread_attr_t attr; pthread_attr_init(&attr); //pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//属性分离 pthread_t tid; pthread_create(&tid,&attr,thr,NULL); int ret; if((ret=pthread_join(tid,NULL))>0){ printf("join err:%d,%s\n",ret,strerror(ret)); } pthread_attr_destroy(&attr); return 0; } //执行结果: gcc -o 03_attrdetach 03_detach.c -lpthread -g yym@ubuntu:~/test/mytest$ ./03_attrdetach I am a thread,self=139627072882432 //线程属性分离之后再编译执行: $ gcc -o 03_attrdetach 03_detach.c -lpthread -g yym@ubuntu:~/test/mytest$ ./03_attrdetach join err:22,Invalid argument查看线程库版本: $ getconf GNU_LIBPTHREAD_VERSION NPTL 2.27 1、主线程退出其他县城不退出,主线程应调用pthread_exit 2、避免僵尸线程 pthread_join pthread_detach pthread_create指定分离属性 分离之后的线程就不能再用join函数回收了 3、malloc和mmap申请的内存可以被其他线程释放 4、在多线程中就不要使多进程了。。应避免再多线程模型中调用fork,除非马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit 5、信号复杂语义很难和多线程共享,应避免在多线程中引入信号机制 6、创建多少个线程? cpu核数*2+2
资源混乱的原因: 1、线程调度随机(顺序不固定) 2、线程资源共享 3、线程没有同步机制 只能解决第3个:加锁 线程同步:就是各个线程有顺序的执行
