Linux下的系统编程——认识进程(七)

简介: Linux下的系统编程——认识进程(七)

一、进程的概念:

1.程序与进程区别:    

程序:死的。只占用磁盘空间。        ——剧本。

进程;活的。运行起来的程序。占用内存、cpu等系统资源。    ——戏。

2.并发:

       并发,在操作系统中,一个时间段中有多个进程都处于已启动运行到运行完毕之间的状态。但,任一个时刻点上仍只有一个进程在运行。

       例如,当下,我们使用计算机时可以边听音乐边聊天边上网。若笼统的将他们均看做一个进程的话,为什么可以同时运行呢,因为并发。

3.单道程序设计:

       所有进程一个一个排对执行。若A阻塞,B只能等待,即使CPu处于空闲状态。而在人机交互时阻塞的出现时必然的。所有这种模型在系统资源利用上及其不合理,在计算机发展历史上存在不久,大部分便被淘汰了。

4.多道程序设计:

       在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之下,相互穿插的运行。多道程序设计必须有硬件基础作为保证。

       时钟中断即为多道程序设计模型的理论基础。并发时,任意进程在执行期间都不希望放弃cpu。因此系统需要一种强制让进程让出 cpu资源的手段。时钟中断有硬件基础作为保障,对进程而言不可抗拒。操作系统中的中断处理函数,来负责调度程序执行。

       在多道程序设计模型中,多个进程轮流使用CPU(分时复用CPu资源)。而当下常见CPu为纳秒级,1秒可以执行大约10亿条指令。由于人眼的反应速度是毫秒级,所以看似同时在运行。

       1s = 1000ms, 1ms = 100Ous,1us = 1000hs       1000000000

实质上,并发是宏观并行,微观串行!         ----推动了计算机蓬勃发展,将人类引入了多媒体时代。

*5.CPU和MMU:

虚拟内存与物理内存映射关系

6.进程控制块PCB:

       我们知道,每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。

      /usr/src/linux-headers-3.16.0-30/include/linux/sched.h.文件中可以查看struct task_struct结构体定义。其内部成员有很多,我们重点掌握以下部分即可:·

   本质:结构体    

   进程id,系统中每个进程有唯一的id,在C语言类型中用pid_t类型表示,其实就是一个非负整数

   文件描述符表

   进程状态:  初始态、就绪态、运行态、挂起态、终止态。

   进程工作目录位置

   *umask掩码 (不是最重要的)

   信号相关信息资源。

   用户id和组id

7.进程状态:

       进程基本的状态有5种。分别为初始态,就绪态,运行态,挂起态与终止态。其中初始态为进程准备阶段,常与就绪态结合来看。

二、环境变量:

1.PATH:

       可执行文件的搜索路径。ls命令也是一个程序,执行它不需要提供完整的路径名/bin/ls,然而通常我们执行当前目录下的程序a.out却需要提供完整的路径名.l/a.out,这是因为PATH环境变量的值里面包含了ls命令所在的目录/bin,却不包含a.out所在的目录。PATH环境变量的值可以包含多个目录,用:号隔开。在shell 中用echo命令可以查看这个环境变量的值:

      echoecho  PATH

2.SHELL:

       当前Shell,它的值通常是: /bin/bash

3.TERM:

      当前终端类型,在图形界面终端下的值通常是xterm。终端类型决定了一些程序的输出显示方式,比如图形界面终端可以显示汉字,而字符终端一般不行。

4.LANG.

        语言和 locale,决定了字符编码以及时间、货币等信息的显示格式。

5.HOME

       当前用户主目录的路径,很多程序需要在主目录下保存配置文件,使得每个用户在运行该程序时都有自己的一套配置。

三、进程控制

*1.fork(重点):

   pid_t fork(void)

   创建子进程。父子进程各自返回。父进程返回子进程pid。 子进程返回 0.

   getpid();getppid();

   循环创建N个子进程模型。 每个子进程标识自己的身份。

 

      (1) fork函数原理:

       (2)创建子进程

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
 
int main(int argc,char *argv[])
{
    printf("before fork -1-\n");
    printf("before fork -2-\n");
    printf("before fork -3-\n");
    printf("before fork -4-\n");
    
    pid_t pid = fork();
    if(pid == -1){
      perror("fork error !\n");
      exit(1);
    }else if(pid == 0){
      printf("child is created\n");
    }else if(pid > 0){
      printf("parent process : my child is %d\n",pid);
    }
 
    printf("end of file\n");
    return 0;
}

 

       循环创建n个子进程

    一次fork函数调用可以创建一个子进程。那么创建N个子进程应该怎样实现呢?简单想

       for(i= 0; i< n; i++)fork()}即可。但这样创建的是N个子进程吗?

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
 
int main(int argc,char *argv[])
{
  int i;
  pid_t pid;
 
  for(i = 0;i < 5;i++){
    if(fork() == 0)
      break;
  }
 
  if(i == 5)
    printf("I'm parent \n");
  else
    printf("I'm %dth child\n",i+1);
 
  return 0;
}

CPU抢夺现象:

如果出现3这种情况,说明子进程没有抢过bash进程,没有争过bash的CPU

避免父进程超越子进程的办法:

增加一个sleep进行延时打印父进程

 
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
 
int main(int argc,char *argv[])
{
  int i;
  pid_t pid;
 
  for(i = 0;i < 5;i++){
    if(fork() == 0)
      break;
  }
 
  if(i == 5){
    sleep(2);
    printf("I'm parent \n");
  }
  else{
        sheep(i);
    printf("I'm %dth child\n",i+1);
  }
  return 0;
}

2.getpid和getppid:

getpid():获取当前进程ID

pid_t getpid(void);

getppid 函数:获取当前进程的父进程 ID

pid_t getppid(void);

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
 
int main(int argc,char *argv[])
{
    printf("before fork -1-\n");
    printf("before fork -2-\n");
    printf("before fork -3-\n");
    printf("before fork -4-\n");
    
    pid_t pid = fork();
    if(pid == -1){
      perror("fork error !\n");
      exit(1);
    }else if(pid == 0){
      printf("child is created,pid = %d,parent-pid:%d\n",getpid(),getppid());
    }else if(pid > 0){
      printf("parent process : my child is %d,my pid :%d,my parent_pid:%d\n",pid,getpid(),getppid());
    }
 
    printf("end of file\n");
    return 0;
}

四、进程共享

       父子进程之间在 fork后。有哪些相同,那些相异之处呢?

      刚fork 之后:

       父子相同处:全局变量.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式...

       父子不同处:

       1.进程ID                        2.fork返回值              3.父进程ID            

       4.进程运行时间             5.闹钟(定时器)            6.未决信号集

l

     似乎,子进程复制了父进程 0-3G 用户空间内容,以及父进程的 PCB,但 pid 不同,真的每fork一个子进程都要将父进程的 0-3G 地址空间完全拷贝一份,然后在映射至物理内存吗?

     当然不是!  父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。

重点注意!        躲避父子进程共享全局变量的知识误区

【重点】:父子进程共享:

      1.文件描述符(打开文件的结构体)

       2. mmap建立的映射(进程间通信详解)

特别的,fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算
法。

五、父子进程gdb调试

gdb调试:

   设置父进程调试路径:set follow-fork-mode parent (默认)

   设置子进程调试路径:set follow-fork-mode child

遇到gdb运行时No symbol table is loaded. Use the “file“ command.的解决方法

  1. 首先,GDB已经报错file找不到了,那可以运行file test检测一下
(gdb) file test
Reading symbols from test...(no debugging symbols found)...done.

       2.发现找不到可执行文件,所以问题应该在于编译时候没有加上ggdb3,重新编译一下

ty@ubuntu:~$ gcc -ggdb3 -o main main.c

        3.编译完成再次执行就没有问题了,问题解决

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
13天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
52 3
|
13天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
39 2
|
23天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
42 5
linux系统服务二!
|
23天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
88 4
linux进程管理万字详解!!!
|
23天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
42 3
linux系统服务!!!
|
7天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
14 3
|
14天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
56 8
|
11天前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
26 1
|
11天前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
13天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
48 3
下一篇
无影云桌面