Chinaunix首页 | 论坛 | 博客
  • 博客访问: 285856
  • 博文数量: 38
  • 博客积分: 706
  • 博客等级: 上士
  • 技术积分: 390
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-05 09:09
文章分类

全部博文(38)

文章存档

2013年(23)

2012年(15)

我的朋友

分类: LINUX

2012-12-14 10:42:23

fork函数
    一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被成为子进程(child process)。fork函数被调用一次,但返回两次,两次返回的唯一区别是子进程的返回值是0,而父进程的返回值是新的子进程的进程ID;子进程可以调用getppid以获取其父进程的进程ID。
    其中,子进程获得父进程数据空间、堆和栈的副本,但是父、子进程并不共享存储空间部分,而共享正文段。
    在fork之后是父进程先执行还是子进程先执行是不确定的,取决于内核所使用的调度算法。如果要求父、子进程之间互相同步,也要求某种形式的进程间通信。如果父进程在子进程之前终止,则会将子进程的父进程改变为int进程(即由init进程领养)。
    
exec函数
    进程待用exec函数执行另一个程序时,该进程执行的程序完全替换为新程序,而新程序从main函数开始执行,但前后的进程ID不改变。exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈。

exit函数
    进程有5种正常终止方式:
    (1)在main函数内执行return语句(等效于调用exit)。
    (2)调用exit函数,其操作包括调用各终止处理程序,然后关闭所有标准I/O流等。
    (3)调用_exit或_Exit函数,即无需进行终止处理程序或信号处理程序而直接终止。
    (4)进程的最后一个线程在其启动例程中执行返回语句。但是该线程的返回值不会用做进程的返回值。当最后一个线程从其启动历程返回时,该进程以终止状态0返回。
    (5)进程的最后一个线程调用pthred_exit函数。进程终止状态总是0.
    进程的3种异常终止方式:
    (1)调用abort,产生SIGABRT信号。
    (2)当进程接收到某些信号时,信号可由进程自身、其他进程或内核产生。
    (3)最后一个线程对“取消”请求做出响应。
    不管进程如何终止,最后都会为相应进程关闭所有打开描述符,释放它所使用的存储器等。
    对于三个终止函数(exit、_exit和_Exit),实现这个的方法是,将其退出状态作为参数传递给函数,而在最后调用_exit时,内核将退出状态转换成终止状态。在异常终止情况下,内核产生一个指示其异常终止原因的终止状态。在任意情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。
    子进程在父进程之前终止时,内核为每个终止子进程保存了一定量的信息,父进程调用wait或waitpid时,可以得到这个信息(信息至少包括进程ID、终止状态、使用的CPU时间总量)。内核可以释放终止进程所使用的所有存储区,关闭所有其打开文件。一个已经终止、但是父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占用的资源)的进程被成为僵死进程。ps(l)命令将僵死进程的状态打印为Z。因此,除非父进程等待获得子进程的终止状态,否则子进程终止后就会变成僵死进程。而被init进程领养的进程,终止时init就会调用wait函数获取其终止状态,防止系统有很多僵死进程。
    
wait函数
    当进程正常或异常终止时,内核就向其父进程发送SICHLD信号。父进程可以选择忽略该信号(系统默认该动作),或者提供一个该信号发生时即被调用执行的信号处理程序。
    调用wait或waitpid的进程时:
    ·如果其素有子进程都还在运行,则阻塞。
    ·如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
    ·如果它没有任何子进程,则立即出错返回。
    如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回。但如果在任意时刻调用wait,则进程可能会阻塞。而wait和waitpid的区别在于waitpid有多个选项,可以控制其等待的进程和是否进行阻塞。
    POSIX.1规定终止状态用定义在中的各个宏来查看。有四个互斥的宏可以用来取得进程终止的原因,名字均以WIF开始。
    WIFEXITED     若为正常终止子进程返回的状态,则为真;可执行WEXITSTATUS取终止状态的低8位
    WIFSIGNALED   若为异常终止子进程返回的状态,则为真;可执行WTERMSIG,取终止进程的信号编号
    WIFSTOPPED    若为当前暂停子进程的返回状态,则为真;可执行WSTOPSIG,取暂停进程的信号编号
    WIFCONTINUED  若暂停后继续的子进程返回状态,则为真;仅用于waitpid

system函数        
    因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值:
    (1)如果fork失败或者waitpid返回除了EINTR之外的出错,则system返回-1,而且errno中设置了错误类型值。
    (2)如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。
    (3)否则所有三个函数(fork、exec和waitpid)都执行成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明。
    再看看Linux版本的system函数源代码,以加深对system函数的理解:    

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/wait.h>
  4. #include <errno.h>
  5. #include <unistd.h>

  6. int system(const char * cmdstring)
  7. {
  8.     pid_t pid;
  9.     int status;
  10.     
  11.     if(cmdstring == NULL)
  12.     {
  13.         return (1);
  14.     }
  15.     
  16.     if((pid = fork())<0)
  17.     {
  18.         status = -1;
  19.     }
  20.     else if(pid == 0)
  21.     {
  22.         execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
  23.         -exit(127); //子进程正常执行则不会执行此语句
  24.     }
  25.     else
  26.     {
  27.         while(waitpid(pid, &status, 0) < 0)
  28.         {
  29.             if(errno != EINTER)
  30.             {
  31.                 status = -1;
  32.                 break;
  33.             }
  34.         }
  35.     }

  36.     return status;
  37. }
    备注1:
    根据进程退出的定义,只要能够调用到/bin/sh,并且执行shell过程中没有被其他信号异常中断,都算正常结束。即不管shell脚本返回什么值,是0或非0,都算正常结束。即使shell脚本不存在或没有权限执行返回,也算是正常执行结束。
    备注2:
    正确判断system函数调用shell脚本是否正确执行,需要进行三个条件的判断:
    ·system函数返回值不为-1
    ·WIFEXITED为真
    ·0 == WEXITSTATUS为真
    备注3:
    如果shell脚本不存在或没有权限执行,虽然正常返回,并且WIFEXITED为真,但WEXITSTATUS为127或126等值,因此调用的shell脚本的返回值最好不要使用127或126等值,最好从1开始递增。
    
    判断shell脚本是否正常执行的完整代码示例:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/wait.h>
  4. #include <sys/types.h>

  5. int main()
  6. {
  7.     pid_t status;
  8.     
  9.     status = system("./test.sh");
  10.     
  11.     if (-1 == status)
  12.     {
  13.         printf("system error!");
  14.     }
  15.     else
  16.     {
  17.         printf("exit status value = [0x%x]\n", status);
  18.         
  19.         if (WIFEXITED(status))
  20.         {
  21.             if (0 == WEXITSTATUS(status))
  22.             {
  23.                 printf("run shell script successfully.\n");
  24.             }
  25.             else
  26.             {
  27.                 printf("run shell script fail, script exit code: %d\n", WEXITSTATUS(status));
  28.             }
  29.         }
  30.         else
  31.         {
  32.             printf("exit status = [%d]\n", WEXITSTATUS(status));
  33.         }
  34.     }

  35.     return 0;
  36. }

阅读(2059) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~