2019-07-04 11:44:40 sinat_33384994 阅读数 18

最近在看csapp3e,看到第8章异常控制流。这章会简单的介绍多进程程序,介绍最好的工具就是那个进程图,对于初学有很大的帮助。以下内容为读书心得。

 

  • 理解linux多进程程序的关键在于书中强调的那4点,需要结合所有的4条内容才能准确理解多进程。

第1条:fork()函数调用1次,返回两次。一次返回给父进程(调用进程),一次返回给子进程。

以书中的一个例子解释(图8-15)

//图8-15
#include "csapp.h"

/* $begin fork */
/* $begin wasidefork */
int main() 
{
    pid_t pid;
    int x = 1;

    pid = Fork(); //line:ecf:forkreturn
    if (pid == 0) {  /* Child */
        printf("child : x=%d\n", ++x); //line:ecf:childprint
        exit(0);//两段代码唯一的区别
    }

    /* Parent */
    printf("parent: x=%d\n", --x); //line:ecf:parentprint
    exit(0);
}
/* $end fork */
/* $end wasidefork */

运行结果是

 

用户代码不能保证并发的执行顺序(在我的机器中是先执行父进程,再执行子进程)。

得到的进程图是这样的

wait a minute,为什么是这样的,关键还在于那句话,fork()函数调用1次,返回两次。

从fork()函数执行之后,我们就拥有了两个进程,跑的是相同的代码,但是操作的是不同的地址空间。

(这个例子中if条件分支利用返回给父进程和子进程的值不同的特点,让两个进程的逻辑流流向了不同的方向)

还有第3条,相同但是独立的地址空间。

子进程会复制一套父进程的地址空间,二者在内容上是一样的,但是,是各自独立的私有地址空间。

两者拥有完全一致的用户栈、本地变量、堆、全局变量、代码,但是两者是独立的,没有联系,只是内容一样。

所以,再fork之后,两个进程是独立运行(也就是操作系统完成用户模式和内核模式的上下文切换的并发),全局变量和局部变量是独立的但是跑的代码内容是一样也就是说,两个进程使用相同的代码操作着各自的私有地址空间)。

 

考虑书中的另一个例子(练习题8.2)。在C代码看来,两者唯一的区别就是在if代码块中一个有exit(0),另一个没有。

但是这足以改变代码的运行逻辑。

//练习题8.2
#include "csapp.h"

/* $begin fork */
/* $begin wasidefork */
int main() 
{
    pid_t pid;
    int x = 1;

    pid = Fork(); //line:ecf:forkreturn
    if (pid == 0) {  /* Child */
        printf("child : x=%d\n", ++x); //line:ecf:childprint
    }

    /* Parent */
    printf("parent: x=%d\n", --x); //line:ecf:parentprint
    exit(0);
}
/* $end fork */
/* $end wasidefork */

运行结果为

 

对比图8-15的运行结果,我们会发现输出结果中好像父进程的代码多执行了一次。实际上,这条代码是子进程运行的结果。

绘制练习题8.2的进程图就一目了然了。

 

结合两段代码和对应的进程图,可以看出

1、fork函数的给父进程和子进程的返回值的不同改变了父子进程的代码起点。

2、exit(0)完成了进程的终止任务,进而影响了父子进程运行的代码终止位置。

 

2016-11-03 16:14:00 qq_34427969 阅读数 201

Linux进程与程序管理

      自学Linux也有一段时间了,但是总是感觉没有什么特别大的进展,总之就是现在学习Linux进入了一个很大的迷茫区,不知道应该如何去学习。现在开始今天的总结,也就是Linux中进程和程序的管理。

一、  进程(process)和程序(program)的概念

程序:通常是安装在硬盘中的软件,一个二进制文件

进程:通常理解就是进程就是进行中的程序,也就是说程序在触发后,执行者的权限与属性的,程序的程序代码与所需数据都会被加载到内存中,然后就产生了进程。

    其实在Linux系统中触发任何一个事件都会产生一个进程,系统会自动赋予这些进程一个ID,称为PID。同时依据触发这个进程的用户和相关属性关系,给予这个PID一组有效的权限设置。

    说到进程,那就分为父进程和子进程了。

    就是说一个程序或者命令被触发后就会被产生一个PID,在这个进程执行过程中继续触发了一个程序或者命令,就会产生一个PPID,子进程产生于父进程。

      关于进程的自启动问题

      当你发现关闭一个进程,过了一会发现这个进程又出现了,

这就是这个进程自动启动了,只需要找到这个进程的父进程,连同父进程一起关闭。

      其实每次登陆shell就会产生一个PID。当前bash为所有进程的父进程。

二、   Linux中关于多人多任务环境

Linux迷人之处就在于多人多任务的环境。也就是说

Linux系统中可以多人同时登陆,并且每个用户所具有的权限都是不一样的,当然root用户的权限是没有限制的。同样的除了root用户没有限制,每个人的权限都是有一些限制的。

      多重登陆环境的七个终端窗口

      在Linux中有6个字符型界面的登录窗口,1个图形化界面的登录窗口。可以使用【Alt】+F1…F6在不同窗口之间来回切换。且每个窗口之间登录的用户还可以是不同用户。

      多任务行为

      Linux系统可以让cpu在各个工作间进行切换,目前Linux使用的多任务切换行为是一种非常棒的机制,几乎可以将PC的性能整个压榨出来,使得性能非常好。

      特殊的进程管理行为

      相信使用Windows的用户都经历过死机的情况,但是当你使用Linux系统,几乎可以说Linux系统几乎是不死机的。假如你使用Linux系统的时候,突然系统挂掉了,没法动了,此时Linux系统中的多用户环境就起作用了,可以使用【Alt】+【F1】~【F7】来进行切换到其他的终端机窗口,然后ps -aux 命令找出刚才的错误进程,然后杀一下,在回到刚才的终端机窗口就好了。

      工作管理:

      在单一终端下,可以同时进行多项工作,如:一边复制数据,一边查询文件。每一项工作都由独立的子进程来完成,他们的父进程就是当前终端对应 bash 的那个进程。

对于终端来说分为前台和后台

前台:你可以控制于执行命令的那个环境(串行工作)

后台:可以自行运行的工作,无法使用 ctrl+c 终端它(并行工作)

所谓工作管理就是,同时进行多个工作的时候应该如何管理。

举例来说:

   # cp file1 file2 &

   在这一串命令中,重点就是&的功能,他表示将文件file1复制到文件file2中,而且放置于后台执行。

   而且当这个命令执行完毕后,系统将会在你的终端显示完成的消息。

 

   当然工作管理不仅仅是这么简单。

   在输入一个命令后,在该命令的后面加上一个&代表将该命令丢到后台执行,此时bash会给这个命令一个工作号码。

当然工作管理以及后台执行命令就要熟悉的使用数据流重定向这个功能了。

   查看当前工作状态的命令:jobs [-lrs]

   选项与参数

   -l : 除了列出job number与指令串之外,同时列出PID的号码

   -r : 仅列出正在后台运行的工作

   -s : 仅列出正在后台中暂停的工作

      将当前的工作丢到后台中暂停: 【ctrl】-z

Eg: # vim ~/.bashrc

在vim的一般模式下,按下【ctrl】-z这两个按键

将后台工作拿到前台来处理: fg

      fg %jobnumber

先用jobs观察工作,然后再将工作取出

 

让工作在后台的状态变成正在运行中:bg

      bg %jobnumber

先用jobs命令观察后台工作,然后让后台工作变成正在运行

 

管理后台当中的工作: kill

 # kill -signal %jobnumber

选项与参数

-l : 列出目前kill能够使用的信号有哪些

Signal:代表给予后面接的工作什么样的指示

-1 : 重新读取一次参数的配置文件(类似reload)

-2 : 代表与【Ctrl】-c 相同的动作

-9 : 立即强制删除一个工作

-15: 以正常的程序方式终止一项工作

Kill后面接的数字默认回事PID,如果想要管理bash的工作控制,就要加上%数字了

 

 

程序管理 :

查阅系统上正在运行的程序

ps:将某个时间点的程序运作情况截取下来

ps aux    观察系统所有的程序数据

ps -lA    观察所有系统的数据 

psaxjf   连同程序输的状态

选项与参数

-A : 所有的process都显示出来

-a : 不与terminal有关的所有process

-u : 有效使用者(effective)

 

仅观察自己bash相关的程序 : ps -l

使用ps -l 仅列出与你的操作环境(bash)相关的程序

 

观察系统所有程序 : ps aux

一般情况下ps aux会按照PID的顺序来排序显示

 

动态观察程序的变化 : top

相对于ps截取一个时间点的程序状态,top则可以持续侦测程序运作的状态

选项与参数

-d : 后面可以接秒数,就是整个程序画面更新的秒数。预设是5秒

-b : 以批次的方式执行top

-n : 与-b搭配,意义是需要进行几次top的输出结果

-p : 指定某些个PID来进行观察检测而已

 

 

三、  关于系统内存的管理

程序在运行的过程中就会占用系统内存,在使用Linux系统命令行的时候,我们无法像在Windows那样安装一个什么图形化的软件来查看系统占用多少。

此时就需要一些命令来观察系统内存的使用情况

 

观察系统内存的使用情况 : free

选项与参数

-b : 直接输入free的时候,显示的单位是kb,我们可以使用b,m,k,G,来显示单位

-t : 在输出的结果中显示物理内存和swap的总量

 

 

阅系统与核心的相关信息 :uname

选项与参数:

-a : 所有系统相关的信息,包括底下的数据都会被列出来

-s : 系统的核心名称

-r : 核心的版本

-m : 本系统的硬件名称

-p : cpu的类型

-I : 硬件的平台

 

观察系统启动时间和工作负载 :uptime

显示系统已经开机多久时间了

 

追踪网络或插槽文件 : netstat

选项与参数

-a : 将目前系统上所有的联机、监听、socket数据都列出来

-t : 列出tcp网络封包的数据

 

分析核心产生的讯息 : dmesg

系统开机的时候核心侦测系统的硬件

侦测系统资源变化 : vmstat

 

 


2018-04-12 22:10:53 qq_32768743 阅读数 136

Linux系统中的进程按功能可以分为三类:

  • init进程:引导和初始化进程
  • daemon进程:常驻进程(系统服务)
  • 普通进程:用户启动的程序

Linux系统启动流程

BIOS:硬件启动
MBR:Master Boot Record
GRUB:操作系统引导程序
加载内核
init:第一个进程
runlevel:相关应用程序
这里写图片描述

Linux引导

BIOS

BIOS:Basic Input and Output System
基本输入输出系统,一般保存在主板的ROM中
计算机通电后首先运行的是BIOS,主要完成两个部分的功能:

  • 通电自检
  • 寻找启动设备

MBR

MBR:Master Boot Record
Linux启动过程中执行MBR中的前446个字节

GRUB

  • GRUB是Linux发行版中普遍使用的引导程序。
  • GRUB相关文件保存在/boot/grub目录中。
  • 其中主要的配置文件为/boot/grub/grub.conf

init进程

init进程是Linux系统运行第一个进程
其主要功能包括:

  • 调用/etc/rc.d/rc.sysinit文件对系统进行初始化
  • 挂载文件系统
  • 根据运行级别启动相关服务和程序

Linux的运行级别:

0:关机
1:单用户模式
2:不带网络模式的多用户
3:普通多用户模式
4:未使用
5:图形化界面
6:重新启动

  • 通过/etc/inittab修改默认运行级别
  • 每个级别对应的启动服务保存在/etc/rc.d/*.d中
  • 使用runlevel命令可以查看当前和上一次运行级别
  • 使用init命令可以改变当前运行级别
2018-03-19 20:10:20 lkjasdgfh 阅读数 10157

程序

定义:通常为二进制文件存放在存储媒介中(硬盘,光驱,软盘等),已物理文件的形式存在。

启动程序,通常要运行某个文件,这个文件就是程序,程序其实是存放在磁盘中的一个二进制文件。

进程

程序被触发后,执行者的权限与属性,程序的程序代码与所需要的数据等都会被加载到内存中,操作系统给予这个内存内的单元
一个标识符(PID),可以说进程就是一个运行中的程序。

用户在启动程序之后,程序会被加载到内存之中,成为一个个体,那就是进程。运行一个程序5次就产生5个进程。

线程

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

由于同一进程的多个线程共享同一地址空间,所以代码段,数据段是共享的,如果定义一个函数(存储在代码段),各线程都可以进行调用,如果定义个全局变量(存储在数据段),在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

概括一下:
程序是一个文件存放在硬盘上。
进程是正在运行的程序在内存中的单元。
线程 与进程类似,不过更轻量级,是进程下更小的单元。

参考内容:Linux进程与线程的区别

2019-05-21 21:05:49 a_hang_szz 阅读数 18

Linux程序和进程

1.什么是程序
程序是二进制文件,占用磁盘空间
2.什么是进程
运行中的程序
所有的数据都在内存中
需要占用更多的系统资源(CPU,物理内存)

3.pcb进程控制块
实际上是一个结构体
里面放了很多数据
4.进程的五种状态
在这里插入图片描述5.父进程子进程(fork)
子进程是父进程的一份拷贝,唯一的区别就是他们的进程ID是不同的
fork函数
int fork(void)
函数有两个返回值父进程返回值为子进程的ID,子进程的返回值为0.
6.写函数了解父子进程之间的关系
pid_t(pid的一种数据类型)
getpid(得到当前进程的进程id)
子进程创建成功以后,代码执行位置?
父进程执行到哪里,子进程就从哪里开始执行
即(fork函数之后);
父子进程的执行顺序?
不一定,谁先抢到CPU资源谁先执行
7.进程相关的命令
ps
ps aux
ps aux | grep +进程名(更加详细的查找某个进程的详细信息)

kill:给进程发送一个信号
kill -l 查看kill的所有信号
kill 9 +进程的pid 杀死某个进程

打开另外一个终端杀死一个死循环进程进程必死无疑打开另外一个终端杀死一个死循环进程进程必死无疑

8.父子进程之间能通过全局变量进行通信吗?

不能
两个进程之间的内存不能共享

9.exec函数族
让父子进程执行不相干的操作
能够替换进程地址空间中的源代码.text段
当前程序中调用另外一个应用程序
execl(“绝对路径”,“占位”,“参数”,NULL);
NULL相当于一个哨兵,当函数运行到NULL则意味着参数结束

execl("/bin/ls",“ls”,"-la",NULL);(实例)

进程回收

1.孤儿进程
爹生孩子
爹先死,孩子还活着,孩子叫做孤儿进程
孤儿被init进程领养,init进程变成孤儿进程的父亲
目的:为了释放子进程占用的系统资源
①进程结束之后,能够释放用户区空间
②释放不了pcb,必须由父进程释放

2.僵尸进程
子进程死了(虽然死了还占用系统资源,需要释放pcb),父进程还活着,父进程不去释放子进程的pcb,子进程就变成了僵尸进程
3.进程回收
函数wait-阻塞函数
pid_t wait(int* status);
返回值
-1:回收失败,已经没有子进程了
大于0:回收子进程对应的pid
参数:status
判断子进程是如何死的
①正常退出
②某个信号杀死
waitpid–

Linux进程和程序

阅读数 21

没有更多推荐了,返回首页