创建进程

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;
    }
}
 
 
 
 
posted @ 2015-05-12 00:40  张仕传  阅读(201)  评论(0编辑  收藏  举报