嵌入式Linux系统编程学习之十Linux进程概述

文章目录


前言

  进程是一个程序一次执行的过程,是操作系统动态执行的基本单位。
  进程的概念主要有两点:
  第一,进程是一个实体。每个进程都有自己的虚拟地址空间,包括文本区、数据区和堆栈区。文本区域存储处理器执行的代码;数据区域存储变量和动态分配的内存;堆栈区域存储着活动进程调用的指令和本地变量。
  第二,进程是一个“执行中的程序”,它和程序有本质的区别。程序是静态的,是一些保存在磁盘上的指令的有序集合;而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建、调度和消亡的过程,是Linux的基本调度单位。只有当处理器赋予程序生命时,它才能成为一个活动的实体,称之为进程。
  内核的调度器负责在所有的进程间分配CPU执行时间,称为时间片(time slice),它轮流在每个进程分得的时间片用完后从进程那里抢回控制权。

提示:以下是本篇文章正文内容,下面案例可供参考

一、进程标识

  OS(操作系统)会为每个进程分配一个唯一的整形ID,作为进程的标识号(PID)。
  进程O是调度进程,常被称为交换进程,它不执行任何程序,是内核的一部分,因此也被称为系统进程。
  进程除了自身的ID外,还有父进程ID(PPID),也就是说每个进程都必须有它的父进程,操作系统不会无缘无故产生一个新进程。
  所有进程的祖先进程是同一个进程,它叫作 init 进程,ID为1,init进程是内核自举后的第一个启动的进程。init 进程负责引导系统、启动守护(后台)进程并且运行必要的程序,它不是系统进程,但它以系统的超级用户特权运行。

二、进程的用户ID与组ID(进程的运行身份)

  进程在运行过程中,必须具有一个类似于用户的身份,以便进行进程的权限控制。默认情况下,哪个登陆用户运行程序,该程序进程就具有该用户的身份。例如,假设当前登录用户为gotter,他运行了ls程序,则ls程序在运行过程中就具有gotter的身份,该ls进程的用户ID和组ID分别为gotter和gotter所属的组。这种类型的ID叫作进程的真实用户ID和真实组ID。真实用户ID和真实组ID可以通过函数getuid()和getgid()获得。
  与真实ID对应,进程还具有有效用户ID和有效组ID的属性,内核对进程的访问权限检查时,它检查的是进程的有效用户ID和有效组ID,而不是真实用户ID和真实组ID。默认情况下,用户的有效用户ID和有效组ID与真实用户ID和真实组ID是相同的。有效用户ID和有效组ID通过函数geteuid()和getegid()获得。
代码如下(示例):

	#include <stdio.h>
	#include <stdlib.h>
	#include <unistd.h>
	int main()
	{
		printf("uid:%d gid:%d euid:%d egid:%d\n", getuid(), getgid(), geteuid(), getegid());
		return 0;
	}
	shell > id
	uid=500(ghaha) gid=500(ghaha) groups=500(ghaha)

  编译生成可执行文件a.out,程序文件的属性可能为:

	-rwxrwxr-x	1 ghaha 	ghaha	12132 Oct	709:26 a.out

  执行结果可能为:

	shell>./a.out
	uid:500 gid:500 euid:500 egid:500

  现在将 a.out 的所有者可执行属性改为s:

	shell>chmod u+s a.out
	shell>ll
	-rwsrwxr-x 1 ghaha ghaha 12132 Oct 7 09:26 a.out

  此时改另外一个用户 gotter 登录并运行程序 a.out:

	shell>id
	uid=502(gotter) gid=502(gotter) groups=502(gotter)
	shell>./a.out
	uid:502 gid:502 euid:500 egid:502

  可以看到,进程的有效用户身份变为了 ghaha,而不是 gotter 了,这是因为文件 a.out 的访问权限的所有者设置了 s 的属性,设置了该属性以后,用户运行 a.out 时, a.out 进程的有效用户身份将不再是运行 a.out 的用户,而是 a.out 文件的所有者。
  s 权限最常见的例子是 /usr/bin/passwd 程序,它的权限位为:

	shell>ll /usr/bin/passwd
	-r-s- -x- -x  1 root  root   16336 Feb 13  2003 /usr/bin/passwd

  我们知道,用户的用户名和密码是保存在 /etc/passwd (后来专门将密码保存在 /etc/shadow,它是根据 /etc/passwd 文件来生成 /etc/shadow 的,它把所有口令从 /etc/passwd 中移到了 /etc/shadow 中。这里用到的是影子口令,它将口令文件分成两部分:/etc/passwd 和 /etc/shadow,此时 /etc/shadow 就是影子口令文件,它保存的是加密的口令,而 /etc/passwd 中的密码全部变成 x )下的。
  通过 ls -l 查看 /etc/passwd 这个文件,你会发现,这个文件普通用户都没有可写的权限,那我们执行 passwd 的时候确实能够修改密码,也就是说,任何一个用户运行该程序时,该程序的有效身份都将是 root (用普通用户身份去执行这个操作的时候,它会暂时得到文件拥有者 root 的权限),而这样 passwd 程序才有权限读取 /etc/passwd 文件的信息。

三、进程的状态

  进程是程序的执行过程,根据它的生命周期可以划分成3种状态,

	时间片 ———————————— 就 ←———————————— 因为等待资源分配而唤醒
	  |	调度 —————————— 绪				  		  |
	  |	 |										  |
	  |	 |										  |
	  |	 ↓										  |
	 执  行 ————— 因为等待某个资源而睡眠 ———————→ 等 待
  • 执行态:该进程正在运行,即进程正在占用CPU
  • 就绪态:进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片
  • 等待态:进程不能使用 CPU,若等待事件发生(等待的资源分配到)则可将其唤醒

四、Linux下的进程结构及管理

  Linux 系统是一个多进程的系统,它的进程之间具有并行、互不干扰等特点,也就是说,进程之间是分离的任务,拥有各自的权利和责任。其中,每个进程都运行在各自的独立的虚拟地址空间,因此,即使一个进程发生了异常,它也不会影响到系统的其他进程。进程中各段如下所示:
进程中的数据段:

高地址 存放传递参数及环境变量
---------- 堆栈
----------
----------
----------
---------- BSS 数据段
---------- 数据段(可读/只读)
---------- 数据段
低地址 代码段

进程的调用:

						   ______________
						   |	     |	|
						   |用户进程	 ↓  |	用户态
						   |____________|
		   中断或系统调用——→______________
						   |		  | |
						   |内核进程	  ↓ |	内核态
						   |____________|

  Linux中的进程包含以下几个部分:

  • “数据段”是存放全局变量、常数及动态数据分配的数据空间。数据段分成普通数据段(包括可读可写/只读数据段,存放静态初始化的全局变量或常量)、BSS 数据段(存放未初始化的全局变量)及堆(存放动态分配的数据)
  • “正文段”存放的是 CPU 执行的机器指令部分
  • “堆栈段”存放的是子程序的返回地址、子程序的参数及程序的局部变量等

 一些进程相关的信息:
  进程 process:是 OS 的最小单元,大小位 4GB,其中 1GB 给 OS,3GB 给进程 {代码区 堆 栈}。
  ps:查看活动进程
  ps -aux:查看各个进程的状态,包括运行、就绪、等待等状态
  ps -aux | grep ‘aa’:查找指定(aa)进程
  ps -ef:查看所有进程的 PID、PPID 等信息
  ps -aux:看 %cpu(cpu使用量)和 %mem(内存使用量)
  stat状态 {S就绪 T中断 R运行 Z僵尸}
  via.c &:&表示后台运行
  jobs:查看后台任务,fg 1把后台任务带到前台,ctrl+z 把进程带入后台
  kill -9:进程号→杀掉某个进程,top 显示前20条进程,动态改变
  pgrep ‘vi’:查找进程
  nice:改变优先级
  crontab:计划任务、定时操作等


上一篇:文本操作find cut sort wc sed awk


下一篇:用户管理初级(上)