Linux系统环境编程之进程1

发布于:2025-06-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

1.引言

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

程序是静态的概念,gcc xxx.c –o pro 磁盘中生成pro文件,叫做程序。

进程是程序的一次运行活动, 通俗点意思是程序跑起来了,系统中就多了一个进程。

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

a.使用ps指令查看 实际工作中,配合grep来查找程序中是否存在某一个进程。ps -aux | grep

b.使用top指令查看,类似windows任务管理器

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

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

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

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

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

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

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

问5. C程序的存储空间是如何分配?

2.进程创建实战

使用fork函数创建一个进程 pid_t fork(void); 

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

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

(1)一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的一父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork使子进程处理此请求。父进程则继续等待下一个服务请求到达。

(2)一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec(我们将在8.10节说明exec)。

fork编程实战:

一个现有进程可以调用fork函数创建-个新进程。

#include <unistd.h>

pid_ t fork (void) ;

返回值:子进程中返回0,父进程中返回子进程ID.出错返回-1

由fork创建的新进程被称为子进程(child process)。fork函 数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。fork使 子进程得到返回值0的理由是:一 个进程只会有个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID (进程ID 0总是由内核交换进程使用,所以一个子进程的进程ID不可能为0)。

子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父、子进程并不共享这些存储空间部分。父、子进程共享正文段(见7.6节)。

由于在fork,之后经常跟险着exec,所以以在的很多实现并不执行一个父进程数据段、栈和堆的完全复制。作为替代,使用了写时复制(Copy On Write, COW)技术。这些区域由父、子进程共享,而且内核将它们的访问权限改变为只读的。如果父、子进程中的任一 个试图修改这些区域,则内核只为修改区域的那块内存制作一一个副本, 通常是虚拟存储器系统中的一页 。Bach[ 19861)的9.2节和McKusick等1996的5 6节和5.7节对这种特征做了更详细的说明。

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

int main(){

       pid_t pid;
       pid_t pid1;

       pid = getpid();
       printf("before fork pid is : %d\n",pid);

       fork();

       pid1 = getpid();
       printf("after fork pid is : %d\n",pid1);

       return 0;
}
 

进一步创建进程获取fork的返回值
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){

       pid_t pid;
       pid_t pid1;

       pid = getpid();
       printf("before fork pid is : %d\n",pid);

       pid_t retpid = fork();

       pid1 = getpid();
       printf("after fork pid is : %d\n",pid1);

       if(retpid > 0){
                printf("this is father pid , father fork : %d\n",retpid);
       }
       else if(retpid == 0){
               printf("this is child pid, child fork : %d \n",retpid);
       }

       return 0;
}

vfork函数 也可以创建进程,与fork有什么区别?

关键区别一: vfork 直接使用父进程存储空间,不拷贝。

关键区别二: vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

//进程,vfork与fork的区别
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){

        int cnt = 0;

       pid_t retpid = vfork();

       if(retpid > 0){
               while(1){
                        printf("this is father pid , father fork : %d\n",retpid);
                        sleep(1);
               }
       }
       else if(retpid == 0){
               while(1){
                         printf("this is child pid, child fork : %d \n",retpid);
                        sleep(1);
               }
       }

       return 0;
}

进程退出

正常退出

1.Main函数调用return

2.进程调用exit(),标准c库

3.进程调用_exit()或者_Exit(),属于系统调用

补充:

1.进程最后一个线程返回

2。最后一个线程调用pthread_exit

异常退出

1.调用abort

2.当进程收到某些信号时,如ctrl+C

3.最后一个线程对取消(cancellation)请求做出响应

不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。

对上述任意一种终止情形、我们都希望终u止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_ exit和_ Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。 在任心一种情况下,该终止进程的父进程都能用wait或waitpid函数(在下一节说明)取得其终止状态。

//退出子进程
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(){

        int cnt = 0;

       pid_t retpid = fork();

       if(retpid > 0){
               while(1){
                       printf("cnt : %d",cnt);
                        printf("this is father pid , father fork : %d\n",retpid);
                        sleep(1);
               }
       }
       else if(retpid == 0){
               while(1){
                printf("this is child pid, child fork : %d \n",retpid);
                sleep(1);
                cnt++;
                if(cnt == 3){
                        exit(0);
                        }
               }
       }

       return 0;
}

//退出子进程,并获取子进程退出编号
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

        int cnt = 0;

        int status = 0;

       pid_t retpid = vfork();

       if(retpid > 0){
               wait(&status);
               while(1){
                       printf("father wait child end! status is : %d\n",WEXITSTATUS(status));
                       printf("cnt : %d\n",cnt);
                        printf("this is father pid , father fork : %d\n",retpid);
                        sleep(1);
               }
       }
       else if(retpid == 0){
               while(1){
                printf("this is child pid, child fork : %d \n",retpid);
                sleep(1);
                cnt++;
                if(cnt == 3){
                        exit(0);
                        }
               }
       }

       return 0;
}

为啥要等待子进程退出?

父进程等待子进程退出 并收集子进程的退出状态。

子进程退出状态不被收集,变成僵死进程(僵尸进程)

区别: waip使调用者阻塞,waitpid有一个选项,可以使调用者不阻塞

waitpid函数:

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

//退出子进程,并获取子进程退出编号
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

        int cnt = 0;

        int status = 0;

       pid_t retpid = vfork();

       if(retpid > 0){
               wait(&status);
               while(1){
                       printf("father wait child end! status is : %d\n",WEXITSTATUS(status));
                       printf("cnt : %d\n",cnt);
                        printf("this is father pid , father fork : %d\n",retpid);
                        sleep(1);
               }
       }
       else if(retpid == 0){
               while(1){
                printf("this is child pid, child fork : %d \n",retpid);
                sleep(1);
                cnt++;
                if(cnt == 3){
                        exit(2);
                        }
               }
       }

       return 0;
}
 

孤儿进程

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

//孤儿子进程
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

        int cnt = 0;

        int status = 0;

       pid_t retpid = fork();

       if(retpid > 0){
                printf("this is father pid , father fork : %d\n",retpid);
       }
       else if(retpid == 0){
               while(1){
                printf("this is child pid, child fork : %d \n",retpid);
                printf("this is a guer,father fork is : %d\n",getppid());
                sleep(1);
                cnt++;
                if(cnt == 3){
                        exit(2);
                }
         }
        }
       return 0;
}
 


网站公告

今日签到

点亮在社区的每一天
去签到