创建进程
system系统调用
#include <stdlib.h>
int system(const char *string);
system函数传递给/bin/sh –c 来执行string所指定的命令。
string中可以包含选项和参数。
如果没有找到/bin/sh,函数返回127,如果出现其他错误返回-1,成功返回0,但如果string为NULL,返回一个非0值。
int main(void)
{
printf(“%d\n”, system(“ls –l”));
return EXIT_SUCCESS;
}
fork系统调用
#include <unistd.h>
pid_t fork(void);
fork执行成功,向父进程返回子进程的PID,并向子进程返回0,这意味着fork即使只调用一次,也会返回两次。
fork创建的新进程是和父进程(除了PID和PPID)一样的副本。
父进程和子进程之间有点区别,子进程没有继承父进程的超时设置(使用alarm调用)、父进程创建的文件锁,或者未决信号。
int main(void) { pid_t child = fork(); if(child == -1) { printf("call fork error\n"); return -1; } if(child == 0) { printf("is child\n"); } else { printf("child pid is %d\n", child); } return 0; }
你不能预计父进程是在它的子进程之前还是之后运行,它的执行是无序的,是异步的。
fork的异步行为意味着你不应该在子进程中执行依赖与父进程的代码,反之亦然。
fork调用可能失败,原因是系统上已经运行了太多进程,已经超过了允许它执行的最大进程数。
fork执行失败,会向父进程返回-1,而且不创建子进程。
fork过程包括把父进程全部内存映像复制给子进程,这个过程很缓慢。
UNIX的设计者创建了vfork调用,vfork调用也创建新进程,但它不产生父进程的副本。
Linux已经使用了写时复制技术,因此Linux的fork和UNIX的vfork一样快。
int execve(const char *path, const char *arg, char * const envp[]);
fork创建了一个新的进程,产生一个新的PID。
execve用被执行的程序完全替换了调用进程的映像。
execve启动一个新程序,替换原有进程,所以被执行进程的PID不会改变。
execve函数接受三个参数。
–path-要执行的文件完整路径;
–argv-传递给程序完整参数列表,包括argv[0],它一般是执行程序的名字;
–envp-是指向执行execed程序的环境指针,可以设为NULL。
int main(void)
{
char *args[] = { "/bin/ls", "-l", NULL };
execve("/bin/ls", args, NULL);
return 0;
}
用fork或者exec函数创建了一个新进程,为了收集新进程的退出状态并防止出现僵死进程(zombie process),父进程应该调用waitpid等待子进程的终止。
什么是僵死进程?
–一个僵死进程是在父进程有机会用wait或者waitpid收集它退出状态之前就终止的子进程。
–之所以被称为僵死进程是因为他虽然死掉了,但依然在进程表中存在。
–子进程退出后分配给它的内存和其他资源都被释放,但它还是在内核进程表中保留了一条,内核在父进程回收子进程的退出状态前一直保留它。
–有一两个僵死进程不算什么问题,但一旦一个程序频繁执行fork或者exec却又不能收集退出状态,那么最终将会填满进程表,这会影响性能,可能导致系统重新启动。
什么是孤儿进程(orphan process)
–孤儿进程是一个父进程在调用wait或者waitpid之前就已经退出的子进程。此时init进程成为子进程的父进程。
–init进程为子进程的父进程收集退出状态,从而避免出现僵死进程。
wait和waitpid函数可以收集子进程的退出状态。
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
stauts保存子进程的退出状态。
pid为等待进程的PID,它能接受下表列出的4种值中的一个
值 |
描述 |
-1 |
等待任何PGID等于PID的绝对值子进程 |
1 |
等待任何子进程 |
0 |
等待任何PGID等于调用进程的子进程 |
>0 |
等待PID等于pid的子进程 |
options规定waitpid调用的行为应该如何。
–WNOHANG-导致waitpid在没有子进程退出的时候立即返回;
–WUNTRACED-意味着它应该因为存在没有报告状态的进程而返回。
wait函数例子
int main(int arg, char *args[]) { pid_t pid = fork(); int status; if (pid == -1) { printf("fork failed\n"); return 0; } if (pid == 0) { printf("child process start\n"); sleep(2); printf("child process end\n"); return 0; } else { printf("parent process start\n"); wait(&status); printf("parent process end\n"); return 0; } }
waitpid函数例子
int main(int arg, char *args[]) { pid_t pid = fork(); int status; if (pid == -1) { printf("fork failed\n"); return 0; } if (pid == 0) { printf("child process start\n"); sleep(2); printf("child process end\n"); return 0; } else { printf("parent process start\n"); waitpid(pid, &status, 0); printf("parent process end\n"); return 0; } }