Chinaunix首页 | 论坛 | 博客
  • 博客访问: 253774
  • 博文数量: 45
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 673
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-10 13:50
文章分类
文章存档

2010年(3)

2009年(15)

2008年(27)

我的朋友

分类: LINUX

2008-10-08 14:32:51

execl(执行文件)  
相关函数:
fork,execle,execlp,execv,execve,execvp

表头文件:
  #include

定义函数:
  int execl(const char * path,const char * arg,....);

函数说明:
  execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。

返回值:
  如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。

范例:
  #include
main()
{
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char * )0);
}

执行  /*执行/bin/ls -al /etc/passwd */
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd





===============================================================================
wait and waitpid

当父进程通过fork创建了子进程之后, 父进程和子进程的执行顺序是无法控制的. 如果想控制, 有两种办法: 使用vfork创建或者父进程调用等待函数wait.


1. 当进程终止时, 会向其父进程发送SIGCHLD信号, 这个异步事件可以在父进程运行的任何时候发生, 包括正常和异常终止两种. 调用wait和waitpid的进程可能会有以下三种情况:

   1. 阻塞(如果其所有的子进程都还在运行)
   2. 带子进程的终止状态正常返回(其中一个子进程终止)
   3. 出错返回(没有子进程)

原型如下:
#include
#include
pid_t wait(int *statloc);
函数返回: 若成功则为进程ID,若出错则为-1.
参数说明:
statloc: 如果是不是空指针, 则子进程的返回状态保存在该指针指向的整型变量中; 如果是空指针, 则忽             略返回状态.



2. waitpid函数:
如果一个进程有若干个子进程, 那么只要有一个子进程返回, wait就返回. 如果要等待一个指定的子进程, 有两种方法. 第一个种, 早期的UNIX必须调用wait, 然后把返回的pid和期望pid做比较, 如果不是期望的, 把该pid保存起来, 继续调用wait, 直到进程终止. 第二种是使用waitpid.
#include
#include
pid_t waitpid(pid_t pid, int *statloc, int options);
函数返回: 若成功则为进程ID, 若出错则为-1.
参数说明:
pid:

    * pid == -1 等待任一子进程. 这个时候waitpid与wait等效.
    * pid > 0     等待其ID与pid相等的子进程.
    * pid == 0 等待其组ID与调用进程的组ID的任一子进程.
    * pid < -1    等待其组ID等于pid绝对值的任一子进程.

对于waitpid函数, 如果指定的进程或进程组不存在, 或者调用进程没有子进程都会出错.

options:
这个一参数可以让我们进一步控制waitpid的操作, 此参数或者是0, 或者是下列的逐位或常数之一:
WNOHANG: 若由pid指定的子进程并不立即可用, 则waitpid不阻塞, 此时其返回值为0.
WUNTRACED: 若某实现支持作业控制, 则由pid指定的任一子进程状态已暂停, 且其状态自暂停以来还                       未报告过, 则返回其状态. WIFSTOPPED宏确定返回值是否对应于一个暂停子进程.

3. waitpid和wait的区别:
waitpid提供了wait函数不能实现的3个功能:

    * waitpid等待特定的子进程, 而wait则返回任一终止状态的子进程;
    * waitpid提供了一个wait的非阻塞版本;
    * waitpid支持作业控制(以WUNTRACED选项).


4. 用于检查wait和waitpid两个函数返回终止状态的宏:
这两个函数返回的子进程状态都保存在statloc指针中, 用以下3个宏可以检查该状态:

    * WIFEXITED(status): 若为正常终止, 则为真. 此时可执行

          o WEXITSTATUS(status): 取子进程传送给exit或_exit参数的低8位.

    * WIFSIGNALED(status): 若为异常终止, 则为真. 此时可执行

          o WTERMSIG(status): 取使子进程终止的信号编号.

    * WIFSTOPPED(status): 若为当前暂停子进程, 则为真. 此时可执行

          o WSTOPSIG(status): 取使子进程暂停的信号编号.




======================================================================
Advanced   Programming   in   the   UNIX®   Environment:   Second   Edition  

8.6.   wait   and   waitpid   Functions

When   a   process   terminates,   either   normally   or   abnormally,   the   kernel   notifies   the   parent   by   sending   the   SIGCHLD   signal   to   the   parent.   Because   the   termination   of   a   child   is   an   asynchronous   eventit   can   happen   at   any   time   while   the   parent   is   runningthis   signal   is   the   asynchronous   notification   from   the   kernel   to   the   parent.   The   parent   can   choose   to   ignore   this   signal,   or   it   can   provide   a   function   that   is   called   when   the   signal   occurs:   a   signal   handler.   The   default   action   for   this   signal   is   to   be   ignored.   We   describe   these   options   in   Chapter   10.   For   now,   we   need   to   be   aware   that   a   process   that   calls   wait   or   waitpid   can

Block,   if   all   of   its   children   are   still   running

Return   immediately   with   the   termination   status   of   a   child,   if   a   child   has   terminated   and   is   waiting   for   its   termination   status   to   be   fetched

Return   immediately   with   an   error,   if   it   doesn 't   have   any   child   processes

If   the   process   is   calling   wait   because   it   received   the   SIGCHLD   signal,   we   expect   wait   to   return   immediately.   But   if   we   call   it   at   any   random   point   in   time,   it   can   block.


#include   wait.h>

pid_t   wait(int   *statloc);

pid_t   waitpid(pid_t   pid,   int   *statloc,   int   options);


 
Both   return:   process   ID   if   OK,   0   (see   later),   or   1   on   error
 


The   differences   between   these   two   functions   are   as   follows.

The   wait   function   can   block   the   caller   until   a   child   process   terminates,   whereas   waitpid   has   an   option   that   prevents   it   from   blocking.

The   waitpid   function   doesn 't   wait   for   the   child   that   terminates   first;   it   has   a   number   of   options   that   control   which   process   it   waits   for.

If   a   child   has   already   terminated   and   is   a   zombie,   wait   returns   immediately   with   that   child 's   status.   Otherwise,   it   blocks   the   caller   until   a   child   terminates.   If   the   caller   blocks   and   has   multiple   children,   wait   returns   when   one   terminates.   We   can   always   tell   which   child   terminated,   because   the   process   ID   is   returned   by   the   function.

For   both   functions,   the   argument   statloc   is   a   pointer   to   an   integer.   If   this   argument   is   not   a   null   pointer,   the   termination   status   of   the   terminated   process   is   stored   in   the   location   pointed   to   by   the   argument.   If   we   don 't   care   about   the   termination   status,   we   simply   pass   a   null   pointer   as   this   argument.

Traditionally,   the   integer   status   that   these   two   functions   return   has   been   defined   by   the   implementation,   with   certain   bits   indicating   the   exit   status   (for   a   normal   return),   other   bits   indicating   the   signal   number   (for   an   abnormal   return),   one   bit   to   indicate   whether   a   core   file   was   generated,   and   so   on.   POSIX.1   specifies   that   the   termination   status   is   to   be   looked   at   using   various   macros   that   are   defined   in   wait.h> .   Four   mutually   exclusive   macros   tell   us   how   the   process   terminated,   and   they   all   begin   with   WIF.   Based   on   which   of   these   four   macros   is   true,   other   macros   are   used   to   obtain   the   exit   status,   signal   number,   and   the   like.   The   four   mutually-exclusive   macros   are   shown   in   Figure   8.4.

We 'll   discuss   how   a   process   can   be   stopped   in   Section   9.8   when   we   discuss   job   control.



8.5.   exit   Functions  


Figure   8.4.   Macros   to   examine   the   termination   status   returned   by   wait   and   waitpid   Macro
  Description
 
WIFEXITED(status)
  True   if   status   was   returned   for   a   child   that   terminated   normally.   In   this   case,   we   can   execute


WEXITSTATUS   (status)


to   fetch   the   low-order   8   bits   of   the   argument   that   the   child   passed   to   exit,   _exit,or   _Exit.
 
WIFSIGNALED   (status)
  True   if   status   was   returned   for   a   child   that   terminated   abnormally,   by   receipt   of   a   signal   that   it   didn 't   catch.   In   this   case,   we   can   execute


WTERMSIG   (status)


to   fetch   the   signal   number   that   caused   the   termination.

Additionally,   some   implementations   (but   not   the   Single   UNIX   Specification)   define   the   macro


WCOREDUMP   (status)


that   returns   true   if   a   core   file   of   the   terminated   process   was   generated.
 
WIFSTOPPED   (status)
  True   if   status   was   returned   for   a   child   that   is   currently   stopped.   In   this   case,   we   can   execute


WSTOPSIG   (status)


to   fetch   the   signal   number   that   caused   the   child   to   stop.
 
WIFCONTINUED   (status)
  True   if   status   was   returned   for   a   child   that   has   been   continued   after   a   job   control   stop   (XSI   extension   to   POSIX.1;   waitpid   only).
 



===============================================================================

wait 函数的参数 status

wait 函数原型
        #include
        #includewait.h>
        pid_t wait(int *status)

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的子进程已经退出,如果让它找到了这样一个变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁会返回。如果没有找到这样的进程,wait就会一直等待,直到找到为止。

参数status用来保存被收集进程再退出时的一些状态,它是一个指向int类型的指针,但如果对之个子进程如何死掉毫不在意,只想把僵尸进程消灭掉(一般都是这样),就把它设为null   pid = wait (NULL)

如果status的值不为null,wait就会把子进程推出时的状态取出并存入其中。指出了子进程是正常退出还是非正常退出,以及正常退出是的返回值,或者被那一个信号结束 等信息。  这些信息存放在一个整数的不同二进制数中,所以常规办法很难读取, 所以设计了一套专门的宏(macro)来完成这项工作。

  WIFXITED(status)

 这个宏指出子进程是否位正常推出的,如果是 他将返回一个非零值。

  WEXITATUS(status)
          ($:/usr/include/sys
          $ grep -i wexit wait.h
          # define WEXITSTATUS(status)  __WEXITSTATUS(__WAIT_INT(status)))

当WIFEXITED 返回非零值时,可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WIFEXITED(status)就会返回5.如果子进程不是正常退出的, WIFEXITED就返回0

实例:

#include
#includewait.h>
#include
main(){
int status;
pid_t pc,pr;
pc=fork();
if(pc<0);
printf("error ocurred!\n");
else if(pc==0){
pritnf("this is a child\n",getpid());
exit(3);
}
else {
pr=wait(&status);
if(WIFEXITED(status)) { /*如果WIFEXITED(status)返回非零值*/
printf(this child process %d exit normally\n",pr);
printf(the reuurn code is %d\n", WEXITATUS(status));
}
else  /*如果WIFEXITED(status)返回零值*/
printf("the child process %d exit abnormally\n",pr);
}
}
 
 
 结果:
    $./wait2
 this is child with pid of 4244
 the child process 4244 exit noramally
 the return code is 3




===================================================================================
WIFEXITED/WEXITSTATUS/WIFSIGNALED

f the exit status value (*note Program Termination::) of the child
process is zero, then the status value reported by `waitpid' or `wait'
is also zero. You can test for other kinds of information encoded in
the returned status value using the following macros. These macros are
defined in the header file `sys/wait.h'.

-- Macro: int WIFEXITED (int STATUS)
     This macro returns a nonzero value if the child process terminated
     normally with `exit' or `_exit'.

-- Macro: int WEXITSTATUS (int STATUS)
     If `WIFEXITED' is true of STATUS, this macro returns the low-order
     8 bits of the exit status value from the child process. *Note
     Exit Status::.

-- Macro: int WIFSIGNALED (int STATUS)
     This macro returns a nonzero value if the child process terminated
     because it received a signal that was not handled. *Note Signal
     Handling::.

子进程的结束状态返回后存于status,底下有几个宏可判别结束情况
WIFEXITED(status)如果子进程正常结束则为非0值。
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真
WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。
WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
WSTOPSIG(status)取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏。





==================================================================================
APUE--僵尸进程 wait() waitpid()
前边文章提到fork与vfork可以产生一个新进程,当子进程使命结束时会调用exit函数。但是调用exit并不会使子进程完全消失,而是转为一个僵 尸进程(zombie)。僵尸进程已将原进程占用的绝大部分内存空间释放,也几乎不占用CPU,它不错任何事情,只是等待父进成来获取原子进程的结束信 息。僵尸进程的存在有其实际意义,它可以为程序员提供许多重要信息,如子进程结束时的状态(正常结束还是异常结束),子进程占用的CPU时间等等,下边的 代码将演示如何产生一个zombie
/***zombie.c***/
#include
#include
#include
#include
int main()
{  pid_t pid;
    if((pid=fork())<0)
   {printf("fork error");
    exit(0);
    }
    else if(pid==0)  /*child process exit ant wait its parent to fetch its exit status*/
      exit(0);
     else if(pid>0)
     sleep(10);   /*parten process sleep for 10s so thar we can see the zombie*/
   if(wait(NULL)==-1)
    printf("wait error");
    printf("parent exit");
   exit(0);
}

编译,运行
$gcc -o zombie zombie.c
$./zombie &
此时在终端运行ps -l 查看进程信息有
$ps -l
F S  UID  PID   PPID   C PRI  NI ADDR  SZ     WCHAN  TTY        TIME      CMD
4 S   0   10460 10139  0  75   0  -   1419    wait   pts/0    00:00:00    bash
0 S   0   24484 10460  0  78   0  -   346     -      pts/0    00:00:00    zombie
1 Z   0   24485 24484  0  78   0  -   0       exit   pts/0    00:00:00    zombie
0 R     0 24821 10460  0  76   0  -   1273    -      pts/0     00:00:00    ps
可以看到
1 Z     0 24485 24484  0  78   0  -          0           exit      pts/0    00:00:00    zombie
中第二列(即进程状态)为Z(zombie)

zombie不占用内存也不占用CPU,表面上我们可以不用在乎它们的存在,然而事实上UNIX系统限制了某一时刻能同时存在的进程的最大数目。如果程序不及时清理系统中的zombie,最终会导致进程数过多,当再次需要产生新进程时就会出错。
鉴于上边的原因,我们需要在子进程调用exit后在父进成中调用wait或waipid
#include
#include
pid_t wait(int &statloc);
pid_t waitpid(pid_t pid,int *statloc, int options);
                 Both return:process ID if OK,-1 on error
它们被父进程调用以获取子进程结束信息、清除zombie。当父进成调用这两个函数时
a 阻塞(如果它的子进程还在运行)
b 立即返回子进程结束信息(如果一个子进程已经结束并等待父进程获取信息)
c 返回错误(如果不存在子进程)
 
     两个函数的不同在于wait会令调用者阻塞直至某个子进程终止而waitpid则可以通过设置一个选项来设置为非阻塞,另外waitpid并不是等待第一个结束的进程而是等待参数中pid指定的进程。
     两个函数中的变量statloc是一个指向int型数据的指针。如果此变量不是NULL,则结束的进程的termination status会被保存在statiloc所指向的内存的区域;如果我们不关心termination status,则可以把statloc置为NULL。
     传统的实现中这两个函数返回的整数中特定的比特位被赋予了特定的含义。POSIX.1指定了一些包含在头文件 宏来查看这些termination status
        Macro                                        Description
   WIFEXITED(status)                     如果status是由一个正常结束的进程产生的则值为真,                                         此时我们可以继续使用宏WEXITSTATUS(status)来                                         获取exit或_exit的参数
   WIFSIGNALED(status)                   如果status是由一个异常结束(接受到一个信号)的进                                         程产生的则值为真,此时使用宏WTERMSIG(status)来                                         获取信号数。
   WIFSTOPPED(status)                    如果status是由一个接受到信号目前终止的进程产生的                                         则值为真,此时可以继续调用宏WSTOPSIG(status)来                                         查看是哪个信号导致进程终止。
  
   waitpid的option常量
   WNOHANG   waitpid将不阻塞如果指定的pid并未结束
   WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
waitpid中pid的含义依据其具体值而变
 pid==-1  等待任何一个子进程,此时waitpid的作用与wait相同
 pid >0   等待进程ID与pid值相同的子进程
 pid==0   等待与调用者进程组ID相同的任意子进程
 pid<-1   等待进程组ID与pid绝对值相等的任意子进程

waitpid提供了wait所没有的三个特性:
 1 waitpid使我们可以等待指定的进程
 2 waitpid提供了一个无阻塞的wait
 3 waitpid支持工作控制
以下代码来自APUE page202
Exp:
#include
#include
#include "ourhde.h"
int main(void)
{   pid_t pid;
    if( (pid=fork() )<0)
     err_sys("fork error");
    else if(pid==0){
       if((pid=fork())<0)
        err_sys("fork error");
        else if(pid>0)
         exit(0);  /*parent from second fork == first child */
       /* We're the second child;our parent becomes init as soon as our real parent calls exit() in the statement above. Here's where we'd continue executing,knowing that when we're done,init wil reap our status*/
       sleep(2);
       printf("second child ,parent pid=%d\n",getppid());
       exit(0);
 }
 if(waitpid(pid,NULL,0)!=pid)
   err_sys("waitpid error");
  /* We're the parent (the original process);we continue executing,knowing that we're not the parent of the second child.*/
    exit(0);
}
$a.out
$second child, parent pid = 1


  上述代码通过两次fork防止zombie的产生






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