进程的几种终止方式

(1)正常退出

从main函数返回[return]

调用exit

调用_exit/_Exit

(2)异常退出

调用abort   产生SIGABOUT信号

由信号终止  Ctrl+C [SIGINT]

...(并不完全, 如return/pthread_exit等)

测试[exit/_exit]

//尝试查看该程序的打印输出
int main()
{cout << "In main, pid = " << getpid();  //去掉了endl;//原理:与终端关联,stdout为行缓冲,在文件中,为全缓冲;//详细信息请参考《UNIX环境高级编程》(第三版)8.5节, P188//exit(0);为C库函数,详细解释如下_exit(0);
}

由图可知,系统调用_exit直接陷入内核,而C语言库函数是经过一系列的系统清理工作,再调用Linux内核的;

int main()
{cout << "In main, pid = " << getpid();fflush(stdout);   //增加了刷新缓冲区工作_exit(0);
}

小结:exit与_exit区别

1)_exit是一个系统调用,exit是一个c库函数

2)exit会执行清除I/O缓存

3)exit会执行调用终止处理程序 //终止处理程序如下

终止处理程序:atexit

#include <stdlib.h>
int atexit(void (*function)(void));
//测试
void exitHandler1(void)
{cout << "If exit with exit, the function exitHandler will be called1" << endl;
}
void exitHandler2(void)
{cout << "If exit with exit, the function exitHandler will be called2" << endl;
}int main()
{cout << "In main, pid = " << getpid() << endl;atexit(exitHandler1);   //注意,先注册的后执行atexit(exitHandler2);exit(0);
}

异常终止

int main()
{cout << "In main, pid = " << getpid() << endl;atexit(exitHandler1);atexit(exitHandler2);abort();//exit(0);
}

exec函数族

exec替换进程印象

在进程的创建上,Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。

当我们创建了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行。当然,exec系列的函数也可以将当前进程替换掉。

exec只是用磁盘上的一个新程序替换了当前进程的正文段, 数据段, 堆段和栈段.

函数族信息

#include <unistd.h>
int execve(const char *filename, char *const argv[],char *const envp[]);#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

说明:

execl,execlp,execle(都带“l”, 代表list)的参数个数是可变的,参数以必须一个空指针结束。

execv和execvp的第二个参数是一个字符串数组(“v”代表“vector”,字符串数组必须以NULL结尾),新程序在启动时会把在argv数组中给定的参数传递到main。

名字最后一个字母是“p”的函数会搜索PATH环境变量去查找新程序的可执行文件。如果可执行文件不在PATH定义的路径上,就必须把包括子目录在内的绝对文件名做为一个参数传递给这些函数;

/*总结:l代表可变参数列表,p代表在path环境变量中搜索file文件。envp代表环境变量*/

//示例execlp
int main()
{pid_t pid = fork();if (pid == 0){if (execlp("/bin/pwd", "pwd", NULL) == -1)err_exit("execlp pwd error");}wait(NULL);pid = fork();if (pid == 0){if (execlp("/bin/ls", "ls", "-l", NULL) == -1)err_exit("execlp ls -l error");}wait(NULL);cout << "After execlp" << endl;
}
//示例execve
int main()
{char *const args[] ={(char *)"/bin/date",(char *)"+%F",NULL};execve("/bin/date",args,NULL);cout << "After fork..." << endl;return 0;
}
//示例execle
//1:main.cpp
int main()
{cout << "In main, pid = " << getpid() << endl;char *const environ[] ={"AA=11","BB=22","CC=33",NULL};execle("./hello","./hello",NULL,environ);   //当environ填为NULL时,则什么都不传递cout << "After fork..." << endl;return 0;
}
extern char **environ;
int main()
{cout << "In hello, pid = " << getpid() << endl;cout << "environ:" << endl;for (int i = 0; environ[i] != NULL; ++i){cout << "\t" << environ[i] << endl;}
}
/*
In main, pid = 3572    //PID保持不变
In hello, pid = 3572
environ:AA=11BB=22CC=33
*/
//示例: execve 与 execlp
int main()
{pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid == 0){//示例execvechar *const args[] ={"echoall","myarg1","MY ARG2",NULL};char *const env[] ={"USER=unknown","PATH=/tmp",NULL};execve("./echoall",args,env);}wait(NULL);pid = fork();if (pid == -1)err_exit("fork error");else if (pid == 0){//示例execlpexeclp("./echoall", "echoall", "only one arg", NULL);}wait(NULL);return 0;
}//echoall
int main(int argc, char *argv[])
{for (int i = 0; i < argc; ++i)printf("argv[%d]: %s\t", i , argv[i]);printf("\n");for (char **ptr = environ; *ptr != NULL; ++ ptr)printf("%s\n", *ptr);exit(0);
}

System系统调用

system()函数调用“/bin/sh -c command”执行特定的命令,阻塞当前进程直到command命令执行完毕,system函数执行时,会调用fork、execve、waitpid等函数。

原型:

int system(const char *command);

返回值:

如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。

//示例
int main()
{system("ls -la");return 0;
}

自己动手写system

int mySystem(const char *command)
{if (command == NULL){errno = EAGAIN;return -1;}pid_t pid = fork();if (pid == -1){perror("fork");exit(-1);}else if (pid == 0){execl("/bin/sh","sh","-c",command,NULL);exit(127);}int status;waitpid(pid,&status,0);//wait(&status);return WEXITSTATUS(status);
}int main()
{mySystem("ls -la");return 0;
}

Linux进程实践(3) --进程终止与exec函数族相关推荐

  1. 【Linux系统编程学习】Linux进程控制原语(fork、exec函数族、wait)

    此为牛客Linux C++和黑马Linux系统编程课程笔记. 1. fork函数 1.1 fork创建单个子进程 #include<unistd.h> pid_t fork(void); ...

  2. C语言进程(第三章,exec函数族,execl,execlp,execle,execv,execvp,execve)

    C语言进程(第三章,exec函数族,execl,execlp,execle,execv,execvp,execve) 简介 本文讲解C语言进程中的exec函数族相关知识,相关函数有excel,exec ...

  3. 进程二(进程的消亡以及释放资源,exec函数族的使用)

    进程的消亡以及释放资源 wait();//相当于 waitpid(-1, &status, 0); waitpid(); waitid(); -------wait for process t ...

  4. Linux学习之系统编程篇:exec 函数族

    函数能力:"换核不换壳"(能够替换进程虚拟地址空间中.text 代码段). 作用:让父子进程执行不相干的操作. 效果:有一个运行的程序 A,在 A 中调用另一个程序 B,程序有父子 ...

  5. Linux中fork创建兄弟子进程,验证进程之间全局变量不共享,exec函数族

    文章目录 编程环境: 并行和并发: 并发:一个时间段,处理请求的个数 并行:多个进程同时进行任务分配: PCB 和 进程的五种状态: 进程控制块 PCB: 进程的五种状态: 进程控制块,父进程创建子进 ...

  6. 【Linux系统编程】进程替换:exec 函数族

    00. 目录 文章目录 00. 目录 01. exec函数族 02. 参考示例 2.1 execl函数示例 2.2 execv函数示例 2.3 execlp() 或 execvp()函数示例 2.4 ...

  7. Linux下进程的建立 并附Linux exec函数族

    我们都知道,进程就是正在执行的程序.而在Linux中,可以使用一个进程来创建另外一个进程.这样的话,Linux的进程的组织结构其实有点像Linux目录树,是个层次结构的,可以使用pstree命令来查看 ...

  8. Linux系统编程——进程替换:exec 函数族

    在 Windows 平台下.我们能够通过双击运行可运行程序.让这个可运行程序成为一个进程:而在 Linux 平台.我们能够通过 ./ 运行,让一个可运行程序成为一个进程. 可是,假设我们本来就执行着一 ...

  9. 操作系统实验一 Linux基本操作|实验二 进程管理

    由于当时没存代码,只有实验文档代码截图,文末也可直接获取实验文档. 操作系统实验 目录 实验一 Linux基本操作 实验二进程管理 实验一 Linux基本操作 1实验目的 1.熟悉在Linux操作系统 ...

最新文章

  1. RDLC 2010设计器的数据源无法找到静态类作为数据源
  2. 深度学习框架太抽象?其实不外乎这五大核心组件
  3. 超级玛丽地图java_我的世界超级玛丽地图包
  4. java对灰度值进行线性变换,灰度变换
  5. Android官方开发文档Training系列课程中文版:手势处理之拖拽或缩放
  6. 《从零开始学Swift》学习笔记(Day 40)——析构函数
  7. mysql int的长度
  8. linux 7 路由命令,CentOS7路由、端口和服务排障常用命令
  9. NYOJ a problem is easy
  10. 地理加权回归GWR4.0软件下载与使用
  11. 关于在networkx中使用louvain算法报错的问题
  12. 第一章 .NET体系结构
  13. 爱吃喵粮的小招喵(查找,动态规划)
  14. 数据库表及其字段变量命名神器之codeIf
  15. 最好的 QML 教程,让你的代码飞起来!
  16. windows编写bat脚本删除隐藏文件夹下的所有文件
  17. excel两个表格按照某一数值匹配其他数据
  18. apache上代理转发nuxt ssr服务器渲染 配置
  19. pycharm中basemap的安装
  20. 变频器调试过程中的常用参数设置详解

热门文章

  1. Iterator迭代器接口讲解
  2. kvm虚拟机网络设置隔离模式(一键shell脚本)
  3. 虚拟机CentOS7开机报错:you might must to save “/run/initramfs/rdsosreport.txt“ to a USB stick or /boot
  4. hnust 神奇的序列
  5. JVM学习--(二)内存模型、可见性、指令重排序
  6. MYSQL 的静态表和动态表的区别, MYISAM 和 INNODB 的区别
  7. [笨木头FireFly 02]入门篇2_客户端发送请求,服务器处理请求
  8. 飘逸的python - 字典合并值相加
  9. 关于Const指针的一点补充
  10. 开源一站式移动应用生成平台Jingub系列(0):背景资料介绍