Linux进程的基础(上)

问1.什么是程序,什么是进程,有什么区别?

        程序是静态的概念,gcc  xxx.c -o pro ,磁盘中生成pro文件,叫做程序。进程是程序的一次运行活动,通俗点意思是程序跑起来了,系统中就多了一个进程。

问2.如何查看系统中有哪些进程?

  1. 使用ps指令查看,实际工作中,配合grep来查找程序中是否存在某一个进程。(例:ps  -aux|grep  init)
  2. 使用top指令查看,类似windows任务管理器。

问3.什么是进程标识符?

        每个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证。

        Pid=0:称为交换进程(swapper),作用—进程调度。

        Pid=1:init进程        作用—系统初始化。

        编程调用getpid函数获取自身的进程标识符getpid获取父进程的进程标识符。

问4.什么叫父进程,什么叫子进程

        进程A创建了进程B,那么A叫做父进程,B叫做子进程是相对的概念,理解为人类中的父子关系。

使用fork函数创建一个进程

       #include <unistd.h>
       getpid();//获得该进程的进程号
       pid_t fork(void);

        fork函数调用成功,返回两次。返回值为0,代表当前进程是子进程。返回值非负数,代表当前进程为父进程,调用失败,返回-1。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
        pid_t pid;
        printf("father:pid = %d\n",getpid());

        pid = fork();
        if(pid > 0){
                printf("this is father print,the pid = %d\n",getpid());
        }else if(pid == 0){
                printf("this is chile print,the pid = %d\n",getpid());
        }
        return 0;
}

        判断父子进程:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
        pid_t pid;
        pid_t pid2;
        pid = getpid();//获得该进程的进程号
        printf("before fork:pid = %d\n",pid);

        fork();
        pid2 = getpid();
        printf("after fork:pid = %d\n",pid2);//fork()调用后的进程号

        if(pid == pid2){//如果是父进程则进程号等于fork()调用之前的进程号
                printf("this is father print\n");
        }else{
                printf("this is chile print,the pid = %d\n",getpid());
        }
        return 0;       
}

fork创建一个子进程的一般目的

  1. 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main(){
            pid_t pid;
    
            int data;
            while(1){
                    printf("please input a data:\n");
                    scanf("%d",&data);
                    if(data == 1){
    
                            pid = fork();
                            if(pid > 0){//父进程不工作
    
                            }
                            else if(pid == 0){//子进程每个3秒打印一次pid号
                                    while(1){
                                            printf("do net request,pid = %d\n",getpid());
                                            sleep(3);
                                    }
    
                            }
    
                    }
                    else{
                            printf("wait do nothing\n");
                    }
            }
    
            return 0;
    }
    
  2. 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。

vfork函数

        vfork函数也可以创建进程,与fork函数的关键区别是:vfork直接使用父进程存储空间,不拷贝;vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
        pid_t pid;
        int cnt = 0;
        pid = vfork();
        if(pid > 0){
                while(1){
                        printf("this is father print,the pid = %d\n",getpid());
                        printf("cnt = %d\n",cnt);
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is chile print,the pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3) {
                                exit(0);
                        //      break;    //使用break会破坏cnt的值
                        }
                }
        }
        return 0;
}

进程的退出

正常退出:

  1. main函数调用return
  2. 进程调用exit(),标准c库
  3. 进程调用_exit()或者_Exit(),属于系统调用
  4. 进程最后一个线程返回
  5. 最后一个线程调用pthread_exit

异常退出:

  1. 调用abort
  2. 当进程收到某些信号时,如ctrl+c
  3. 最后一个线程对取消(cancellation)请求做出回应

父进程等待子进程退出

        父进程等待子进程退出并收集子进程的退出状态,子进程退出状态不被收集,变成僵尸进程。收集子进程退出状态的相关函数:

       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);

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

       int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

        status参数:是一个整型数指针;非空:子进程退出状态放在它所指向的地址中;空:不关心退出状态。

        宏WIFEXITED(status),若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit,_exit,或_Exit参数的低8位。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
        pid_t pid;
        int cnt = 0;
        int status = 10;
        pid = fork();
        if(pid > 0){
                while(1){
                        wait(&status);//父进程收到子进程的退出状态后才往下执行
                        printf("child quit,child status = %d\n",WEXITSTATUS(status));//打印退出状态3
                        printf("this is father print,the pid = %d\n",getpid());
                        printf("cnt = %d\n",cnt);
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is child print,the pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 5) {
                                exit(3);//退出状态为3
                        }
                }
        }
        return 0;
}

对于waitpid函数中pid参数的作用解释如下:

        pid==-1        等待任一子进程。就这一方面而言,waitpid与wait等效。

        pid>0            等待其进程ID与pid相等的子进程。

        pid==0          等待其组ID等于调用进程组ID的任一子进程。

        pid<-1           等待其组ID等于pid绝对值的任一子进程。

waitpid的options常量

常量说明
WCONTINUED        若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态
WNOHANG        若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
WUNTRACED        若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应干一个暂停子进程。

孤儿进程

        父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程,Linux避免系统存在过多的孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
        pid_t pid;
        int cnt = 0;
        int status = 10;
        pid = fork();
        if(pid > 0){
                        printf("this is father print,the pid = %d\n",getpid());
                }
        else if(pid == 0){
                while(1){
                        printf("this is child print,the pid = %d,father pid = %d\n",getpid(),getppid());//getppid:获得父进程的pid号
                        sleep(1);
                        cnt++;
                        if(cnt == 5) {
                                exit(3);
                        }
                }
        }
        return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从入门到捕蛇者说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值