linux-c进程控制

4 篇文章 0 订阅
1 篇文章 0 订阅

一.进程相关的概念

1.什么是程序?
答:编译好的二进制文件
2.什么是进程?
答:运行着的程序,
    运行一系列指令的过程,
    在操作系统角度:分配系统资源的基本单位
3.程序与进程的区别?
答:(1) 程序占用磁盘,不占用系统资源
    (2) 内存占用系统资源
    (3) 一个程序对应多个进程,一个进程对应一个程序
    (4) 程序没有生命周期,进程由生命周期
4.单道程序设计与多道程序设计
    单道:每次只能运行一个程序,串行方式进行
    多道:微观上串行,宏观上并行

程序如何转化为进程?
         当程序执行时,操作系统会将可执行程序复制到内存中。

  1. 内核将程序读入内存,为程序分配内存空间。
  2. 内核为该进程分配PID(进程标识符)和其他所需资源。
  3. 把进程放在运行队列中等待执行,程序转化为进程以后就可以被操作系统调度程序执行了。

虚拟内存映像:
         虚拟内存映像是指内核在内存中如何存放可执行文件。
         每当我们创建一个进程时,操作系统就会为该进程分配一个 4GB 大小的虚拟进程地址空间。
         为什么是4G呢?
         这是因为32位计算机cpu的最大寻址空间为4G

在这里插入图片描述

MMU的了解:
   MMU又叫内存管理单元。
   MMU作用:
                      1.用来做虚拟内存与物理内存的映射
                      2.设置修改内存访问级别

在这里插入图片描述如下例:
在这里插入图片描述
         我们在一块虚拟内存中int a = 1,MMU也会在对应的物理地址中找到一块映射过去的内存,实际上a是存在对应的物理地址上的。
         cpu读取的时候是先找到对应的虚拟地址,然后通过MMU的映射关系,从而找到物理地址,然后将值取出。

PCB(进程控制块)的了解:
1.一个结构体struct task_struct,内部成员很多这里就不一以说明 ,其实是我也没有完全理解

重点说一说PCB,每一个进程在运行时都有一个唯一的进程控制块,
操作系统是根据PCB来对并发执行的进程进行控制和管理的,

PCB是进程存在的唯一标识。

PCB存在于上面说的虚拟内存映像中3G-4G的内核区中,

说一说这里面和文件I/O有关的东西,PCB中有一个文件描述符表,这个表中有1024个文件描述符,从0一直到1023,0,1,2对应标准输入,标准输出,标准错误,每次打开文件时都会用到最小的没有被用到的文件描述符,可以看看下面的例子:

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

int main()
{
    close(1);//关闭了文件描述符1 == stdout
    int fd = open("1.log",O_CREAT | O_TRUNC | O_WRONLY ,0644);
    //此时的fd就是1了
    printf("hello world\n");
    //输出到fd指向的文件中
    fflush(stdout);
    //fflush用来刷新缓冲区,
    //如果不刷新缓冲区,不能写入到文件中
    //缓冲区存在与文件描述符结构体中
    close(fd);
    return 0;
}

这段代码中,printf函数会调用write函数,然后write函数会调用底层的sys_write函数,sys_write函数会调用设备驱动,也就是显示器。
二.进程相关函数
1.fork 函数—>(用来创建一个进程)
函数原型: pid_t fork(void);
函数返回值

  1. 失败: -1
  2. 成功: 两次返回值
    父进程返回子进程的ID
    子进程返回 0

2.获取进程ID函数
函数原型:

pid_t getpid(void)—>(获取当前进程的ID)
pid_t getppid(void)—>(获取当前进程父进程的ID)

3.查看进程信息与杀死进程:

init进程是所有进程的祖先
ps aux
ps ajx --可以追述进程之间的血缘关系
kill:
(1)给进程发送一个信号
(2)SIGKILL 9号信号
(3)kill -SIGKILL pid -->杀死进程
或者kill -9 pid

5.循环创建n个子进程

如果在循环中子进程不中断循环,将会出现问题,子进程会在循环中继续创建子进程,那我们就需要再fork完之后把每一次的子进程break除去

//循环创建了5个子进程
#include <stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    int n = 5;
    int i = 0;
    pid_t pid = 0;
    for(i = 0; i < 5; i++)
    {//父进程循环结束
        pid = fork();
        if(pid == 0)
        {
            //son
            printf("I am child , pid  = %d, ppid = %d\n",getpid(),getppid());
            break;        //子进程推出循环的接口
        }
        else if(pid > 0)
        {
            //father
            //printf("I am father ,pid = %d, ppid = %d\n",getpid(),getppid()); 
        }
    }
    sleep(i);
    if(i < 5)
    {
        printf("I am child ,will exit,pid = %d,ppid = %d\n",getpid(),getppid());
    }
    else
    {
        printf("I am parent ,will out pid = %d,ppid = %d\n",getpid(),getppid());                             
    }
    return 0;
}

6.进程共享

    父子进程之间在fork后,有哪些相同之处?那些不同之处?
        父子相同处:全局变量
        			data
        			.text
        			堆
        			栈
        			环境变量
        			用户ID
        			宿主目录
       				进程工作目录
        			信号处理方式
        父子不同处:1. 进程ID
                    2. fork返回值
                    3. 父进程ID
                    4. 进程运行时间
                    5. 定时器
                    6.未决信号集

父子进程满足读时共享,写时复制

7.exec族函数—>执行其他程序
函数所在头文件: #include<unistd.h>
函数原型:

int execl(const char *pathname, const char arg, …/ (char *)NULL */);

int execlp(const char *file, const char arg, …/ (char ) NULL/);
这里比上一个多了一个p,这个p是指的环境变量

file  :要执行的程序
arg 参数列表:
            参数列表最后一个需要一个NULL作为结尾
返回值:
           只有失败才会返回
函数作用:
        将当前进程的.text,data替换为所要加载的程序
        的.text,data,然后让进程从新的.text第一
        条指令开始执行,但是进程的ID不变,换核不换壳

在这里插入图片描述直接把原来的代码段,换成自己的代码段,然后执行。

#include <stdio.h>
#include<unistd.h>

int main()
{
    execlp("ls","ls","-l","--color=auto",NULL);             
    //execl ("/bin/ls","ls","-l","--color=auto",NULL);
    perror("exec err");
    printf("hello\n");
    return 0;
}

8.孤儿进程与僵尸进程
孤儿进程(orphan):父亲死了,子进程被init进程领养
僵尸进程(zombie):子进程死了,父进程没有回收子进程的资源(PCB)
kill命令不能杀死僵尸进程
如何回收僵尸进程:杀死父亲,init领养,负责回收

9.子进程回收(知道子进程的死亡原因)
    函数原型:
        pid_t wait(int *wstatus);
            wstatus: 传出参数
    作用:
        阻塞等待子进程死亡
        回收子进程资源
        查看死亡原因
    函数返回值:
        成功 返回终止的子进程ID
        失败 返回-1
    子进程的死亡原因:
        正常死亡WIFEXITD
            如果WIFEXITED为真,
            	使用WEXITSTATUS得到退出状态
        非正常死亡WIFSIGNALED
            如果WIFSIGNALED为真,
            	使用WTERMSIG得到信号
    函数原型:
        pid_t waitpid(pid_t pid, int *wstatus, int options);
            pid:
                <-1 组ID
                =-1 回收任意                                                 
                >0  回收指定的pid
                =0  回收和调用进程组ID相同组内的子进程
            options:
                设置为0
                	与wait相同也会阻塞
                设置为 WNOHANG 
                	如果当前没有子进程退出的,会立即返回
    函数返回值:
        如果设置了WNOHANG,
        		那么如果没有子进程退出,返回0
        	     否则,返回退出进程的pid
        		失败返回-1
#include <stdio.h>                                                                      
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        printf("I am child,will die!\n");
        sleep(2);
        //return 101;
        //如果这里这么写,那么死亡方式就是正常死亡
        while(1)
        {
            printf("No die!HaHa\n");
            sleep(1);
        }
    }
    else if(pid > 0)
    {
        printf("I am parent,wait for child die!\n");
        int status;
        pid_t wpid = wait(&status);
        printf("wait ok,wpid = %d,pid = %d\n",wpid,pid);
        //判断死亡方式:正常死亡
        if(WIFEXITED(status))
        {
           printf("child exit with %d\n",WEXITSTATUS(status)); 
        }
        //信号杀死
        if(WIFSIGNALED(status))
        {
                     printf("child killedby%d\n",WTERMSIG(status));
         }
         while(1)
         {
             sleep(1);
         }
     }
     return 0;
 }


  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值