Linux进程实践(3) --进程终止与exec函数族
进程的几种终止方式
(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=11 BB=22 CC=33 */
//示例: execve 与 execlp
int main()
{
pid_t pid = fork();
if (pid == -1)
err_exit("fork error");
else if (pid == 0)
{
//示例execve
char *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)
{
//示例execlp
execlp("./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.2 Linux中的进程 --- fork、vfork、exec函数族、进程退出方式、守护进程等分析
fork和vfork分析: 在fork还没有实现copy on write之前,Unix设计者很关心fork之后立即执行exec所造成的地址空间浪费,也就是拷贝进程地址空间时的效率问题,所以引入vfo ...
- Linux系统编程——进程替换:exec 函数族
在 Windows 平台下,我们能够通过双击运行可运行程序,让这个可运行程序成为一个进程.而在 Linux 平台.我们能够通过 ./ 运行,让一个可运行程序成为一个进程. 可是.假设我们本来就执行着一 ...
- exec函数族的使用
作者:王姗姗,华清远见嵌入式学院讲师. exec用被执行的程序完全替换调用它的程序的影像.fork创建一个新的进程就产生了一个新的PID,exec启动一个新程序,替换原有的进程,因此这个新的被exec ...
- Linux进程理解与实践(三)进程终止函数和exec函数族的使用
进程的几种终止方式(Termination) (1)正常退出 从main函数返回[return] 调用exit 调用_exit或者_Exit 最后一个线程从其启动处返回 从最后一个线程调用pthrea ...
- Linux进程实践(1) --Linux进程编程概述
进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...
- jprofiler_监控远程linux服务器的JVM进程(实践)
几天前写了一篇文章,jprofiler_监控远程linux服务器的tomcat进程(实践),介绍了使用jprofiler怎样监控远程linux的tomcat进程,这两天想了想,除了可以监控tomcat ...
- Linux常用指令---kill | killall(终止进程)
kill Linux中的kill命令用来终止指定的进程(terminate a process)的运行,是Linux下进程管理的常用命令.通常,终止一个前台进程可以使用Ctrl+C键,但是,对于一个后 ...
- Linux进程控制——exec函数族
原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是 ...
- Linux进程实践(5) --守护进程
概述 守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭:守护进程的名称通常以d结尾,比如sshd.xinetd.crond.atd等 ...
随机推荐
- 深入理解SpringCloud之引导程序应用上下文
tips:我希望通过这篇文章来给对于bootstrap还不理解的朋友带来帮助.当然这篇文章不仅仅是讲解知识,我更希望给广大朋友带来学习与理解官方文档的一种思路.阅读本文前,建议大家对SpringBoo ...
- ACM Smallest Difference
给定一些不同的十进制数字(distinct decimal digits),您可以通过选择这些数字的非空子集(non-empty subset)并以某种顺序编写它们,从而形成一个整数. 剩下的数字可以 ...
- 对 /dev/shm 认识
一./dev/shm理论 /dev/shm/是linux下一个非常有用的目录,因为这个目录不在硬盘上,而是在内存里.因此在linux下,就不需要大费周折去建 ramdisk,直接使用/dev/shm/ ...
- Swift基础之自定义PUSH和POP跳转动画
之前用OC代码写过PUSH和POP的转场动画,闲来无事,将其转换成Swift语言,希望对大家有帮助,转载请注明.... 如何实现PUSH和POP的转场动画? 首先,创建一个NSObject的类,分别用 ...
- Django 是如何实现用户登录和登出机制的(默认版本-数据库版本)
Django session 字典,保存到数据库的时候是要先序列化的(session.encode方法), 读取的时候反序列化(session.decode),这样比较安全. 一 settings.p ...
- 24 AIDL案例
服务端 MainActivity.java package com.qf.day24_aidl_wordserver; import android.app.Activity; import andr ...
- socket系列之什么是socket
1.什么是socket Socket是应用层与TCP/IP协议族通信的中间抽象层,它是一组接口,应用层通过调用这些接口实现发送和接收数据.一般这种抽象层由操作系统提供或者由JVM自己实现.使用sock ...
- 10 GridView 样式属性
GridView 样式属性: 1,android:numColumns="auto_fit" 显示的列数 如果android:numColumns不设置那么自动每行1列 如下图 2 ...
- 没有文件扩展“.js”的脚本引擎问题解决
安装MinGW的时候提示没有文件扩展".js"的脚本引擎. 原因:系统安装Dreamwear.UltraEdit.EditPlus后修改了.js文件的默认打开方式.当想直接执行js ...
- SSH框架实现仿淘宝购物demo
还记得六月份实习的时候,曾经做过一个电商的项目,项目里面需要实现类似淘宝购物车的移动端的demo,随着项目的进行,再一次跟购物车碰面,但是今天呢,不是移动端的需求,如何使用SSH框架实现类似淘宝的购物 ...