Linux基础知识 - 进程控制相关系统调用

本来想现在Linux上熟悉下进程的有关概念然后去写windowsSDK的,没想到今天Windows蓝屏了,新升级的3.2.2内核打开虚拟机的时候还要升级内核。升就升吧,没想到还错误了。没办法,看来只好在Linux上面待着了。

系统调用:进程控制
fork系统调用
函数作用:创建一个子进程

这几天自己只是熟悉了下进程的概念,然后简单的写了一些小程序。自己写点笔记免的忘掉。

形式:pid_tfork(void);

进程标识符:Linux环境下进程启动时候,系统分配给一个唯一的数值给每个进程,这个数值就称为进程标识符。(感觉跟windows里面的句柄有点像)

      pid_t vfork(void);

进程表示有进程号 PID 和 父进程号 PPID,都是非0整数

说明:使用vfork创子进程时,不会进程父进程的上下文

使用函数getpid获得当前进程号,

返回值:[返回值=-1]子进程创建失败

函数原型Pid_t getpid(void);

      [返回值=0]子进程创建成功

使用函数getppid获得当前进程的父进程号

      [返回值>0]对父进程返回子进程PID

函数原型Pid_t getppid(void);

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("子进程创建失败!");
    } else {
        if (id == 0) {
            printf("子进程工作:PID=%d,PPID=%dn", getpid(), getppid());
        }else
        {
            printf("父进程工作:PID=%d,PPID=%d,子进程PID=%dn", getpid(), getppid(),id);
            sleep(5)
        }
    }
}
控制台输出

下面介绍LinuxC下与进程相关的函数

父进程工作:PID=3173,PPID=2432,子进程PID=3176

exec函数族  在进程中启动另一个程序执行

子进程工作:PID=3176,PPID=3173

这个函数族有6个成员

 

exec函数族函数原型

exit系统调用
函数作用:终止发出调用的进程

#include <unistd.h>

形式:voidexit(int status);

int execl(const char *path, const char *arg, ...);

说明

int execlp(const char *file, const char *arg, ...);

1.      exit返回信息可由wait系统函数获得

int execle(const char *path, const char *arg, ..., char *const envp[]);

2.      如果父进程先退出子进程的关系被转到init进程下

int execv(const char *path, char *const argv[]);

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("子进程创建失败!");
    } else {
        if (id == 0) {
            printf("子进程工作:PID=%d,PPID=%dn", getpid(), getppid());
            sleep(20);
            printf("此时子进程:PID=%d,PPID=%dn", getpid(), getppid());
        }else
        {
            printf("父进程工作:PID=%d,PPID=%d,子进程PID=%dn", getpid(), getppid(),id);
            sleep(5);
            exit(3);
        }
    }
    return 0;
}
控制台输出

int execvp(const char *file, char *const argv[]);

父进程工作:PID=3068,PPID=2432,子进程PID=3071

int execve(const char *path, char *const argv[], char *const envp[]);

子进程工作:PID=3071,PPID=3068

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

此时子进程:PID=3071,PPID=1

system          在进程中开始另一个进程

 

       函数原型

wait系统调用
函数作用:父进程与子进程同步,父进程调用后。进入睡眠状态,直到子进程结束或者父进程在被其他进程终止,

       #i nclude<stdlib.h>
       int system(const char * string);

形式:pid_twait(int *status)

       函数说明
       system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。在调用system()期间     SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
       返回值
        =-1:出现错误
        =0:调用成功但是没有出现子进程
        >0:成功退出的子进程的id

pid_t waitpid(pid_t pid ,int *status,int option)

fork                 从已存在的进程中复制一个新进程(这个进程叫做原来父进程的子进程)

参数:statusè exit是设置的代码

        这是个关键的函数,理解了这个函数也就是进程入门了吧,呵呵

pid è进程号

        废话不多说,先来看看函数原型:

option: WNOHANG|WUNTRACED

          #include<unistd.h>  

WNOHANG:,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去.
WUNTRACED:子进程进入暂停则马上返回,但结束状态不予以理会.

                #include<sys/types.h>  

返回值:如果成功等待子进程结束,则返回子进程PID。后者为-1

          pid_t fork( void);   (pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)

用来检查子进程返回状态的宏

返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1   

WIFEXITED这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值.

函数说明:   一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。   

WEXITSTATUS当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。  

wait函数使用
#include <sys/types.h>
#include <sys/uio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    cid = fork();
    if (cid < 0) {
        perror("子进程创建失败!");
    } else {
        if (cid == 0) {
            printf("子进程工作n");
            printf("子进程PID=%d,PPID=%dn", getpid(),getppid());
            //sleep(20); //1
        } else {
            //wait(NULL);//2
            //sleep(20);//3
            printf("父进程工作n");
            printf("父进程PID=%d,PPID=%dn", getpid(),getppid());
        }
    }
    return 0;
}
针对上述代码作以下分析:

Linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。

1.      当子进程退出时,如果父进程没有wait进行回收资源,子进程就会一直变为僵尸进程(Z)直到父进程退出

我当初一直难以理解的fork函数的返回值。先看下示例代码:

作法:

[cpp]

打开3处注释后执行程序,查看进程状态,如下

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <unistd.h>   
  4. #include <sys/types.h>   
  5.   
  6. int main()  
  7. {  
  8.     //unsigned int result;     
  9.     pid_t result;  
  10.     result=fork();  
  11.     int newret;  
  12.     if (result==-1)  
  13.     {  
  14.         perror("创建子进程失败");  
  15.         exit;  
  16.     }  
  17.     else if (result == 0)  
  18.     {  
  19.         printf("返回值是:%d,说明这是子进程!n 此进程的进程号(PID)是:%dn此进程的父进程号(PPID)是:%dn",result,getpid(),getppid());  
  20.         newret = system("ls -l");  
  21.     }  
  22.     else  
  23.     {  
  24.         sleep(10);  
  25.         printf("返回值是:%d,说明这是父进程!n 此进程的进程号(PID)是:%dn此进程的父进程号(PPID)是:%dn",result,getpid(),getppid());  
  26.         newret = system("ping www.baidu.com");  
  27.     }  
  28.     return 0;  
  29. }     

[root@localhostDebug]# ps -C Process -o pid,ppid,stat,cmd

图片 1

PID PPID STAT CMD

12233 11563S  /root/workspace/Process/Debug/Process

12238 12233Z    [Process] <defunct>

=>可以看到子进程此时的状态时Z(僵尸进程)

 

控制台输出如下

子进程工作

子进程PID=12238,PPID=12233

(20S后…..)

父进程工作

父进程PID=12233,PPID=11563

 

2.      使用wait进行进程同步,父进程直到子进程退出,wait才会结束等待

作法:

打开1,2处注释后执行程序,查看进程状态,如下

[root@ Debug8$] ps -C Process -o pid,ppid,stat,cmd

PID PPID STAT CMD

3425 2432 S  /root/workspace/Process/Debug/Process

3430 3425 S  /root/workspace/Process/Debug/Process

=>父进程与子进程都处于sleep状态

 

控制台输出如下

子进程工作

子进程PID=3430,PPID=3425

(20S后…..)

父进程工作

父进程PID=3425,PPID=2432

 

3. 使用wait进行进程同步,子进程退出后,父进程结束wait等待,同时清空子进程信息,此时子进程不再是僵尸进程

作法:

打开2,3处注释后执行程序,查看进程状态,如下

[root@localhostDebug]# ps -C Process -o pid,ppid,stat,cmd

 PID PPID STAT CMD

本文由太阳集团所有网址16877发布于www.16877.com,转载请注明出处:Linux基础知识 - 进程控制相关系统调用

您可能还会对下面的文章感兴趣: