1、execl():
头文件:#include <unistd.h>
函数原型:int execl(const char *path, const char *arg, ...);
功能:产生一个新程序替换原有的程序执行,原有的进程ID不变。
#include <unistd.h>
#include <stdio.h>
int main()
{
int ret = execl("/mnt/hgfs/Share/0809/review/bubble_sort", "./file", NULL);
if(ret == -1)
{
perror("execl");
return -1;
}
printf("原程序不再执行\n");
return 0;
}说明:
由于产生了一个新的程序将原有的程序替换所以原有的程序将不再执行,printf也就没有打印输出。
2、execlp():
头文件:#include <unistd.h>
函数原型:int execlp(const char *file, const char *arg, ...);
功能:与execl()基本相同,不同的是如果在规定的目录下找不到执行文件它会去PATH环境变量中查找该程序。
int main()
{
int ret = execlp("file", "file", NULL);
if (ret == -1)
{
perror("execl");
return -1;
}
return 0;
}3、execv():
头文件:#include <unistd.h>
函数原型:int execv(const char *path, char *const argv[]);
功能:与execl()基本相同,不同的是它将execl()后面的参数保存在一个字符串指针数组中。
int main()
{
char *a[] = {"file", NULL};
int ret = execv("file", a);
if (ret == -1)
{
perror("execl");
return -1;
}
return 0;
}4、system():
头文件:#include <stdlib.h>
函数原型:int system(const char *command);
功能:调用fork产生子进程,由子进程来调用 /bin/sh -c string来执行参数string所代表的命令,不会使原进程被替换。
实现一个伪终端:
#include <stdlib.h>
#include <stdio.h>
int main()
{
char str[100];
while(1)
{
printf("[root@localhost ~]# ");
fgets(str,100,stdin);
system(str);
}
return 0;
}5、exit()和_exit():
_exit: 直接使进程停止,清除其使用的内存,并清除缓冲区中内容。
exit:在停止进程之前,要检查文件的打开情况,并把文件缓冲区中的内容写回文件才停止进程。
子进程比父进程先退出会形成僵尸进程:
父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。
因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中,直到父进程中断结束。
父进程比子进程先退出:
若父进程比子进程先终止,则该父进程的所有子进程的父进程都改变为init进程。我们称这些进程由init进程领养。其执行顺序大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程ID就更改为1(init进程的ID)。
有init领养的进程不会称为僵尸进程,因为只要init的子进程终止,init就会调用一个wait函数取得其终止状态。这样也就防止了在系统中有很多僵尸进程。
守护进程的创建:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
int daemon_process()
{
// 1、创建子进程,关闭父进程
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid > 0)
{
exit(0);
}
// 2、设置文件的掩码, mode & ~umask
umask(0);
// 3、设置新的会话: 脱离当前会话和终端的控制
if(setsid() < 0)
{
perror("setsid");
return -1;
}
// 4、改变当前的工作目录
if(chdir("/") < 0)
{
perror("chdir");
return -1;
}
// 5、关闭标准输入、标准输出、标准错误
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 6、重定向标准输入、标准输出、标准错误
open("/dev/null", O_RDONLY); // 0
open("/dev/null", O_RDWR); // 1
open("/dev/null", O_RDWR); // 2
return 0;
}
int main()
{
daemon_process();
while(1);
return 0;
}6、wait()和waitpid():
头文件:#include <sys/wait.h>
函数原型:pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
功能:接收退出的子进程,若成功返回进程ID,若出错返回-1。
参数pid为欲等待的子进程识别码:
pid<-1 等待进程组识别码为pid绝对值的任何子进程。
pid=-1 等待任何子进程,相当于wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为pid的子进程。
本文详细介绍了进程控制函数如execl(), execlp(), execv(), system(), exit(), _exit(), wait() 和 waitpid()的功能及使用方法。同时,还探讨了如何避免僵尸进程的产生,以及如何创建守护进程。
348

被折叠的 条评论
为什么被折叠?



