1. 进程的退出
exit 函数用于进程退出
头文件:#include <stdlib.h>
函数原型:void exit(int status);
参数:int status:退出状态值(可以任意写,值规定0 以上的正整数)
返回值:无
_exit 函数用于进程退出
头文件:#include <unistd.h>
函数原型:void _exit(int status);
说明:
1. 如果进程正常退出,则status 一般为0;
2. 如果进程异常退出,则status 一般为非0;
3. 标准C库已经定义两个宏提供使用EXIT_SUCCESS 和 EXIT_FAILURE,正常退出exit(EXIT_SUCCESS ),以及异常退出exit(EXIT_FAILURE)。
exit 与_exit 区别
两者的区别主要是体现在处理过程中,如下图所示:
_exit()函数会直接调用exit 系统调用退出,其间只是清除其使用的内存空间,并销毁其在内核中的各种数据结构。
exit()函数退出时会先自刷新标准IO 总线上残留数据到内核,如果进程注册了“退出处理函”还自动执行这些函数,最后才调用exit 系统调用。
下面用个实例来说明:
代码一:
1 /*****************************************************************************
2 * File Name: exit.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 07:37:27 PM PDT
6 ******************************************************************************/
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <unistd.h>
11
12 int main()
13 {
14 printf("Using exit..\n");
15 printf("This is the end.");
16 exit(0);
17 }
18
运行结果:
代码二:
1 /*****************************************************************************
2 * File Name: exit.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 07:37:27 PM PDT
6 ******************************************************************************/
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <unistd.h>
11
12 int main()
13 {
14 printf("Using exit..\n");
15 printf("This is the end.");
16 _exit(0);
17 }
18
运行结果:
说明:换行符’\n’又刷新缓冲区的作用,所以在第二段代码中,printf(“This is the end.”);没使用’\n’,而且调用_exit结束进程,所以没有打印第二句话。
2. 进程的启动
system 函数用于启动并执行shell 命令
头文件:#include <stdlib.h>
函数原型:int system(const char *command);
返回值:
成功:非0
失败:0
参数列表: const char *command:执行的命令
示例:
1 /*******************************************************************************
2 * File Name: system.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 07:59:07 PM PDT
6 ********************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 int main()
13 {
14 system("ls -l");
15 exit(0);
16 }
运行结果:
Exec 函数族
exec 函数族提供了一种在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。在执行完之后,原调用进程的内容除了进程号外,其他全部都被替换了。
以下是exec函数族的标准接口
示例1:execl
下面展示子进程被创建出来之后执行的代码,以及如何加载这个指定程序。被子进程加载的示例代码:
1 /*******************************************************************************
2 * File Name: child_elf.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 10:18:22 PM PDT
6 ********************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 int main(int argc, char **argv)
13 {
14 printf("[pid:%d]:child_elf\n", (int)getpid());
15 exit(EXIT_SUCCESS);
16 }
17
下面是使用exec 函数簇中的execl 来让子进程加载上述代码的示例:
1 /*****************************************************************************
2 * File Name: exec.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 10:22:45 PM PDT
6 ******************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 int main(int argc, char **argv)
13 {
14 pid_t pid;
15 pid = fork();
16
17 /*父进程*/
18 if(pid > 0)
19 {
20 printf("[pid :%d] parent.\n", (int)getpid());
21 exit(EXIT_SUCCESS);
22 }
23 /*子进程*/
24 if(pid == 0)
25 {
26 printf("[pid:%d]child.\n", (int)getpid());
27 execl("./child_elf", "./child_elf", NULL);
28
29 /*因为执行execl后,.text代码段中的程序代码已被child_elf替代*/
30 printf("NEVER be printed\n");/*不执行*/
31 exit(EXIT_SUCCESS);
32 }
33
34 return 0;
35 }
36
运行结果:
示例2:execv
用一下两行代码代替execl(“./child_elf”, “./child_elf”, NULL);
char *argv[] = {"./child_elf",NULL);
execv("./child_elf",argv);
示例3:execlp
执行linux 命令ls -l
execlp("ls", "ls", "-l", NULL);
示例4:execve
1 /*******************************************************************************
2 * File Name: execlp.c
3 * Author: 谢保成
4 * E-mail: 2446603068@qq.com
5 * Create Time: Fri 18 Aug 2017 10:59:34 PM PDT
6 ********************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 int main()
13 {
14 char *argv[] = {"ls", "-l", NULL};
15 char *envp[] = {"PATH=/bin", 0};
16 execve("/bin/ls", argv, envp);
17
18 return 0;
19 }
20
运行结果:
示例5:execvp
char * argv[] ={ "ls", "-al", 0};
execvp("ls", argv);
注意:
在使用exec 函数族时,一定要加上错误判断语句常见的错误原因有:
1)找不到文件或路径,此时errno 被设置为ENOEN
2)数组argv 和envp 忘记用NULL 结束,此时errno 被设置为EFAULT
3)没有对应可执行文件的运行权限,此时errno 被设置为EACCESS