当前位置: 首页 > news >正文

进程相关及守护进程

一、进程

1.1 wait / waitpid 函数的使用

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *wstatus);
功能:阻塞等待子进程结束,为子进程回收资源
参数:wstatus:子进程退出的状态--如果不关注,可以传NULL0~6:bit位,保存的是中断进程的信号号8~15:bit位,保存的是进程退出的状态WIFEXITED(wstatus):如果进程是正常退出(是否是通过调用exit()函数退出的),返回真WEXITSTATUS(wstatus):获取进程退出的状态,0~255,必须在WIFEXITED返回为真的情况下使用WIFSIGNALED()wstatus:如果进程是被信号中断,这个宏返回trueWTERMSIG(wstatus):返回中断信号进程的信号号,必须在WIFSIGNALED返回为真的情况下使用
返回值:成功返回回收到的子进程的pid,失败返回-1,置位错误码pid_t waitpid(pid_t pid,int *wstatus,int options);
功能:回收子进程的资源
参数:pid:< -1:回收组id为pid的绝对值的子进程的资源传参:-123456,那么会回收组id为123456的子进程的资源-1:回收任意子程序的资源‘0:回收同一进程组的子进程的资源> 0 :回收进程pid == 参数pid,的子进程的资源通过进程的pid,指定回收某个子进程的资源wstatus:子进程退出的状态 -- 如果不关注,可以传NULL0~7:bit位保存的是中断进程的信号号8~15:bit位保存的是进程退出的状态。WIFEXITED(wstatus):如果进程是正常退出(是否是通过调用exit()函数退出的)),返回真WEXITSTATUS(wstatus):获取进程退出的状态,0~255,必须在WIFEXITED返回真的情况下使用WIFSIGNALED(wstatus):如果进程是被信号中断,这个宏返回trueWTERMSIG(wstatus):返回中断进程的信号号,必须在WIFSIGNALED返回真的情况下使用
options:0:表示阻塞回收子进程的资源WNOHANG:非阻塞回收子进程的资源返回值:成功返回回收到的子进程的pid,失败返回-1wait(&wstatus)等价于waitpid(-1,&wstatus,0)
wait(NULL)等价于waitpid(-1,NULL,0)

wait函数的使用实例(回收资源不关注子进程的退出状态)

#include <my_head.h>int main(int argc,const char *argv[]){pid_t ret = 0;ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程sleep(20);printf("子进程,要死了\n");exit(100);//退出的状态为100}else{//父进程//回收资源,不关注子进程的退出状态printf("父进程\n");wait(NULL);//传参NULL,阻塞回收子进程的资源,不关注子进程的状态printf("父进程回收子进程资源完毕\n");sleep(5);printf();}return 0;
}

 运行结果

wait函数的使用实例(回收资源关注子进程的退出状态)

#include <my_head.h>int main(int argc,const char *argv[]){pid_t ret = 0;ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程sleep(5);printf("子进程,要死了\n");exit(100);//退出的状态为100}else{//父进程//回收资源,关注子进程的退出状态int wstatus = 0;pid_t ret;int status,signo;ret = wait(&wstatus);printf("回收到的子进程pid = %d\n",ret);if(WIFEXITED(wstatus)){status = WEXITSTATUS(wstatus);printf("子进程退出的状态值是%d\n",status);}if(WIFSIGNALED(wstatus)){signo = WTERMSIG(wstatus);printf("中断子进程的信号号%d\n",signo);}}return 0;

运行结果:

waitpid使用实例(阻塞方式回收子进程资源,不关注进程退出状态

#include <my_head.h>int main(int argc,const char *argv[]){pid_t ret = 0;ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程sleep(5);printf("子进程,要死了\n");exit(100);//退出的状态位100}else{//父进程//回收资源,不关注子进程退出状态printf("我是父进程\n");waitpid(-1,NULL,0);//传参1NULL,不关注子进程退出状态,阻塞回收子进程的资源printf("父进程回收子进程资源完毕\n");sleep(5);printf("父进程死了\n");}return 0;
}

运行结果:

waitpid使用实例(非阻塞方式回收子进程资源,关注进程退出状态)

#include <my_head.h>int main(int argc,const char *argv[]){pid_t ret = 0;ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程sleep(5);printf("子进程,要死了\n");exit(100);//退出的状态位100}else{//父进程int wstatus = 0;pid_t ret;int sstatus,signo;while(1){printf("我是父进程\n");//非阻塞回收子进程资源,WNOHANGret = waitpid(-1,&wstatus,WNOHANG);if(ret != 0&&ret != -1){printf("回收的子进程pid为%d\n",ret);if(WIFEXITED(wstatus)){sstatus = WEXITSTATUS(wstatus);printf("子进程退出的状态值%d\n",wstatus);}if(WIFSIGNALED(wstatus)){signo = WTERMSIG(wstatus);printf("中断子进程信号号%d\n",signo);}}sleep(1);}  }return 0;
}

运行结果:子进程是否运行完不影响父进程的运行,父进程反复判断,当子进程死了,父进程就回收子进程资源,然后继续运行

1.2 system函数的使用

#include <stdlib.h> --- 所需头文件
int system(const char *command);
功能:通过fork创建一个子进程,在子进程中执行command命令
参数:command:要执行的命令,执行shell脚本,shell命令,可执行程序等
返回值:1、如果command为NULL,或者shell可用,返回0,如果不可用返回非0的数值2、如果子进程无法被创建,那么返回-1,置位错误码3、如果command不可以被执行,返回状态码1274、如果所有的command都执行成功,会返回最后一个shell的返回值。

system使用实例

#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;//使用system执行命令ret = system("ls");return 0;
}

运行结果:

#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;//使用system执行命令ret = system("lcdsc");//shell不可用,返回非0数值printf("ret = %d\n",ret);return 0;
}

运行结果:

#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;//使用system执行多个命令system("ls;pwd");//方式1:使用;作为分隔符,多个命令都会被执行(不论成功失败)return 0;
}

运行结果:

#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;//使用system执行多个命令system("lssq&&pwd");//方式2:使用&&作为分隔符,多个命令都会被执行,//只要有一个失败,后面的命令都不会被执行return 0;
}

运算结果:

#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;//使用system执行多个命令system("lssq||pwd||ls");//方式2:使用||作为分隔符,//只要有一个命令执行成功,后面命令则不会再执行return 0;
}

运行结果:

1.3 守护进程

1.3.1 守护进程的概念

        随着系统的启动而启动,睡着系统的终止而终止,脱离中断运行。

就是系统的服务。

1.3.2 守护进程(daemon)的创建流程

        1、创建一个孤儿进程(为了脱离终端)

        2、设置会话id,创建一个新的会话,新会话即新终端,此终端在后台运行不可视。(脱离终端)

        3、设置工作目录(把此目录设置在根目录,为了保证工作目录一直存在)

        4、设置掩码(设置创建文件的掩码)

        5、对文件描述符重定向(将输入输出重定向到某个文件)

        6、开启自己的服务

1.3.3相关API分析

1.创建一个孤儿进程(为了脱离终端)

使用fork创建一个子进程之后,让父进程直接结束,子进程不要结束

2.设置会话id,创建一个新的会话。

(脱离目前终端,再在后台开一个新的终端)

#include <sys/types.h> 
#include <unistd.h> 
pid_t setsid(void); 
功能:创建一个新的会话,调用者会称为这个会话的组长 
参数: 空 
返回值:成功返回新的会话id,看不到这个终端,只知道新终端的id 失败返回(pid_t) -1 ,置位错误码

3.设置工作目录(为了保证工作目录一直存在)

把目录设置到了根目录,根目录一直存在,也是为了保证新开的终端一直存在。

#include <unistd.h> 
int chdir(const char *path); 
功能:改变进程的工作目录 
参数: path:新的工作目录 
返回值:成功返回0,失败返回-1,置位错误码

4.设置掩码(设置创建文件的掩码)

#include <sys/types.h> 
#include <sys/stat.h> 
mode_t umask(mode_t mask); 功能:设置进程创建文件的掩码 
参数: mask:新的掩码 
返回值:这个函数总是调用成功,返回之前的掩码数值

5.对文件描述符重定向(将输入输出重定向到某个文件)

像prinf,scanf等输入输出函数,都输出到终端,在终端输入,重定向到某个文件之后,输入输出的操作现象就在这个文件中显现了。

#include <unistd.h> 
int dup(int oldfd); 
功能:复制文件描述符,将oldfd复制产生一个新的fd并作为返回值返回 
参数: oldfd:旧的文件描述符 
返回值:成功返回复制出的新的文件描述符,失败返回-1,置位错误码 int dup2(int oldfd, int newfd); 
功能:复制oldfd生成新的newfd 
参数: oldfd:旧的文件描述符 newfd:新的文件描述符 
返回:成功返回复制出的新的文件描述符,失败返回-1,置位错误码

dup的使用

#include <my_head.h> 
int main(int argc, const char *argv[]) 
{ 
// 1.打开一个文件 int oldfd, newfd; oldfd = open("./a.txt", O_RDWR | O_CREAT, 0666); if (-1 == oldfd)PRINT_ERR("open error"); // 
//2.复制文件描述符 // newfd = dup(oldfd); // write(oldfd,"hello",strlen("hello")); // write(newfd," world",strlen(" world"));//都会写入a.txt文件中,oldfd,newfd代表的是同一个文件 close(1); // 关闭标准输出 newfd = dup(oldfd);//复制出的新的文件描述符遵循最小分配原则,由于标准输出1,被关掉了,所以复制出的新的文件描述符是1 printf("11111111111111111\n"); return 0; 
}

dup2使用实例

#include <my_head.h> 
int main(int argc, const char *argv[]) {// 1.打开一个文件 int oldfd, newfd; oldfd = open("./a.txt", O_RDWR | O_CREAT, 0666); if (-1 == oldfd) PRINT_ERR("open error"); newfd = 6; // //2.复制文件描述符 dup2(oldfd,newfd);//将oldfd复制,生成新的文件描述符6 write(oldfd,"hello",strlen("hello")); write(newfd," world",strlen(" world"));//都会写入a.txt文件中,oldfd,newfd代表的是同一个文件 dup2(oldfd,1);//复制出一个新的文件描述符1,旧的1(标准输出)会被关闭 printf("11111111111111111\n"); return 0; 
}

6.开启自己的服务

守护进程创建实例

注意:创建完成之后,看到现象了,九八创建的守护进程杀死

kill -9 进程pid

#include <my_head.h>int main(int argc,const char *argv[]){//1.创建一个孤儿进程pid_t ret;ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程//2.设置会话setsid();//3.设置工作目录chdir("/");//4.设置掩码umask(0);//5.输入输出重定向//创建一个新的文件,作为日志文件int fd = open("/log.txt",O_RDWR|O_CREAT,0666);if(-1 == fd)PRINT_ERR("open log.txt error");//将输入输出重定向到log.txtdup2(fd,0);dup2(fd,1);dup2(fd,3);//开启自己的服务while(1){printf("hello world\n");fflush(NULL);sleep(1);}}else{//父进程exit(EXIT_SUCCESS);//父进程直接退出}return 0;
}

运行现象:


http://www.mrgr.cn/news/50194.html

相关文章:

  • 电脑显示d3dcompiler_47.dll缺失如何修复,马上教你6个修复方法
  • Windows环境下安装使用curl命令
  • 【从零开始的LeetCode-算法】2135. 统计追加字母可以获得的单词数
  • Linux——Harbor(容器镜像 管理项目)
  • c语言字符函数
  • 力扣随机题
  • Django模型优化
  • MySQL表的基本查询上
  • 【Linux】信号(初版)
  • lego-loam imageProjection.cpp源码注释(一)
  • 242.有效的字母异位词
  • 2022年华为杯数学建模竞赛A题论文和代码
  • Datawhale 组队学习 文生图 Prompt攻防 task02随笔
  • 糖基转移酶数据库及代表性文章进展-汇总系列
  • 力扣题解(鸡蛋掉落,两枚鸡蛋)
  • 用html、css和js来实现冒泡排序
  • FPGA驱动HDMI 初级篇
  • 10月15日 -- 11月15日 ,参与《人工智能导论》学习打卡赢B站大会员
  • 饭局上做到这5点,让你轻松和大家打成一片相谈甚欢!
  • Thread类的基本用用法