一、进程

 1.进程的含义

    进程是一个程序执行的过程,进程要使用系统的资源,即会去分配内存资源,cpu的调度

     pcb  是一个结构体,process control block  print circuit board

2.进程和程序的区别

(1)程序:静态   存储在硬盘中代码,数据的集合

(2)进程:动态  存储在内存上

  (3)程序执行的过程,包括进程的创建、调度、消亡   .c ----> a.out-----> process(pid)

        1)程序是永存,进程是暂时的

        2)进程有程序状态的变化,程序没有

        3)进程可以并发,程序无并发

        4)进程与进程会存在竞争计算机的资源

        5)一个程序可以运行多次,变成多个进程  ;一个进程可以运行一个或多个程序

 3.内存的分布

        0-3G,是进程的空间,3G-4G是内核的空间,虚拟地址

        虚拟地址 *  物理内存和虚拟内存的地址 映射表 1page=4k    mmu

a.out是ELF的一种形式,a.out里会放ELF、code 、data

stack:栈区  最大不超过8M 存放局部变量、形参、函数的返回地址

map/share:映射区和共享区 只读、将外面的内存空间映射过来,可减少a.out的空间 放标准库,so

heap:堆区、动态存储空间,由程序员使用和申请

data/bss:全局变量、静态变量区、可读可写 ; bass(未初始化的全局变量)

code:代码区、只读

:面试题

4.进程分类

(1).交互式进程

(2).批处理进程   shell脚本 

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

int main(int argc, char **argv)
{
  while (1)
    {
      printf("$");
      char buf[1024] = {0};
      fgets(buf, sizeof(buf), stdin);
      int len = strlen(buf);
      buf[len - 1] = '\0';
      if (0 == strcmp(buf, "quit") || strcmp(buf, "exit") == 0)
        {
          return -1;
        }
      else
        {
          char *s[5] = {NULL};
          int i = 0;
          s[i] = strtok(buf, " ");
          while (s[++i] = strtok(NULL, " "))
            ;
          //   for(i = 0;i < 5;++i)
          //    {
          //        printf("s[%d] = %s\n",i,s[i]);
          //    }
          pid_t pid = fork();
          if (pid < 0)
            {
              perror("fail fork");
              return -1;
            }

          if (pid > 0)
            {
              wait(NULL);
              continue;
            }
          else if (0 == pid)
            {
              if(execvp(s[0], s)< 0)
              {
                perror("execvp fail");
                return -1;
              }
            }
        }
    }
}

(3).守护进程 :类似杀毒软件,不需要典型输入,自己能运行

5.进程的状态

3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统是最大的管家

linux中的状态,运行态,睡眠态,僵尸,暂停态。

6.进程的作用 

并发,并行区别(同一时刻同时发生)

eg:while (1) { while (1) { 上下左右  发视频} }

7.进程的调度

进程上下文切换

内核主要功能之一就是完成进程调度, 硬件,bios,io,文件系统,驱动

调度算法: other,idle ,rr,fifo

先来先服务->短任务有限->优先级->多级任务队列->时间片轮转

宏观并行

微观串行

8.查询进程相关命令

(1)ps aux : 查看进程相关信息

  • 就绪态、运行态 R
  • 睡眠态、等待态
  • 可唤醒等待态 S
  • 不可唤醒等待态 D
  • 停止态 T
  • 僵尸态 Z
  • 结束态 X
  • 多线程程序 L

(2) top:根据CPU占用率查看进程相关信息,类似windows下任务管理器

(3).kill和killall:发送一个信号; kill -l 查看可以发送的信号;

      kill -2 (发2号信号) PID  15(通知DID关闭信号)

      发送信号+PID对应的进程,默认接收者关闭

      killall -9 (发送信息,强制关闭)进程名 发送信号 进程名对应的所有进程

(4)pstree 显示父子关系图

          pstree -sp 显示更多信息

          pstree -sp[pid]  查看指定的进程的进程数

 

二、进程相关的函数

1.fork();并发运行

   pid_t fork(); 叉子

   特性:(1)一次调用,会返回两次。

             (2)子进程先运行还是父进程先进程,顺序不确定。

             (3)变量不共享。父子之间空间独立,操作互不影响。

             (4)子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。

   功能:通过该函数可以从当前进程中克隆一个同名新进程。

   关系:(1)克隆的进程称为子进程,原有的进程称为 父进程。

             (2)子进程是父进程的完全拷贝。子进程大于父进程。

             (3)子进程的执行过程是从fork函数之后执行。

             (4)子进程与父进程具有相同的代码逻辑。

返回值:int 类型的数字。

               在父进程中:成功 返回值是子进程的pid号  >0;失败 返回-1;

               在子进程中:成功 返回值 0

               失败 无

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

int	main(int argc, char **argv)
{
    printf("start...\n");
    pid_t ret=fork();
    if(ret>0)
    {
        while (1)
        {
            printf("father,发送视频\n");
            sleep(1);
        }
    }
    else if(0==ret)
    {
        while(1)
        {
            printf("child,接受视频\n");
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        return 1;
    }
    return 0;
}

 代码结构:

2.getpid

   pid_t getpid(void);

   功能:获得调用该函数进程的pid

   参数:缺省

   返回值:进程的pid

3.getppid

  pid_t getppid(void);

  功能:获得调用该函数进程的父进程pid号

  参数:缺省

  返回值:返回父进程id号

#include <stdio.h>
#include<string.h>
#include<sys/types.h>
#include <unistd.h>
int a=20;
int	main(int argc, char **argv)
{
    printf("start...\n");
    pid_t ret=fork();
    if(ret>0)
    {
        int i=10;
        while (i--)
        {
            printf("father,发送视频 pid:%d ,ppid:%d a:%d \n",getpid(),getppid(),a);
            sleep(1);
        }
    }
    else if(0==ret)
    {
        int i=10;
        a+=10;
        while(i--)
        {
            printf("child,接受视频 pid:%d ,ppid:%d a:%d \n",getpid(),getppid(),a);
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        return 1;
    }
    printf("a is %d pid:%d ,ppid:%d\n",a,getpid(),getppid());
    return 0;
}

注: 由此可看出变量不共享

4.父子进程的关系

子进程是父进程的副本。子进程获得父进程数据段,堆,栈,正文段共享。

在fork之后,一般情况那个会先运行,是不确定的。如果非要确定那个要先运行,需要IPC机制,取决于操作系统的调度算法。

调度算法:先来先服务;短作业优先;高优先级;时间片轮转;

区别:1)fork的返回值

          2)pid不同

5.父子进程的文件共享问题

情况一:fork之前打开文件 子进程会继承父进程的文件描述符 共用一个offset值

情况二:fork之后打开文件 子进程和父进程各自独立拥有自己的fd 相互之间独立的offset 数据可能形成覆盖 

 父进程可能被覆盖

三、练习

 1.动态生成n个子进程,并打印输出各自进程的pid号

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

int main(int argc, char **argv)
{
  int n=5;
  int i=0;
  printf("father: pid:%d ,ppid:%d \n", getpid(), getppid());
  for (i=0 ; i < 5; ++i)
  {
    pid_t ret = fork();
    if (ret > 0)
    {
      continue;
    }
    else if (0==ret)
    {
      printf("child: pid:%d ,ppid:%d \n", getpid(), getppid());
      break;
    }
    else
    {
      perror("fork");
      return 1;
    }
  }
  return 0;
}

2.fork()&&fork()||fork();

一共五个进程

 3. 设计一个程序,动态生成两个进程,分别向相同的文件中 写入不同的数据,要表明是两个进程同时写入的数据。 父进程1123 186 16:02:10   子进程1124 188 16:02:15

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int main(void)
{
    FILE*fp=fopen("1.txt", "w");
    pid_t pid=fork();
    if(pid>0)
    {
        int i=3;
        while(i--)
        {
            int num=rand()%100+20;
            time_t tm=time(NULL);
            struct tm *tm_info = localtime(&tm);
            fprintf(fp,"father %d num:%d %d:%d:%d\n",getpid(),num,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec);
            fflush(fp);
            sleep(3);
        }
    }
    else if(0==pid)
    {
        int i=2;
        while(--i)
        {
            int num=rand()%100+20;
            time_t tm=time(NULL);
            struct tm *tm_info = localtime(&tm);
            fprintf(fp,"child %d num:%d %d:%d:%d\n",getpid(),num,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec);
            fflush(fp);
            sleep(5);
        }
    }
    else
    {
        perror("fork");
        return 1;
    }
    fclose(fp);
    return 0;
}

补充:

1.ulimit -a 进线程

2. man -k +关键字 模糊搜索

3.time 的两种传参方式

4.grep 查找

面试题

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐