一、进程和线程的概念

1.进程和线程的定义

  进程并不只是一段可以运行的代码,也包含了运行代码所需要的资源。

  在操作系统来看,进程是资源管理的最小单元,而我们又知道,线程是程序执行的最小单元。

  话说回来,Linux系统至少有一个进程,一个程序可以对应多个进程,一个进程只能对应一个程序,一个进程包含一个或多个线程。

  所以,一个进程的组成实体实际是两大部分:资源的集合和线程的集合。进程中的线程是动态的对象, 代表了进程指令的执行。资源,包括地址空间、打开的文件、用户信息等等,由进程内的线程共享。线程有自己的私有数据:程序计数器,栈空间以及寄存器。

  总结来说,在linux系统下,进程主要具有以下四个要素:

  1)有一个程序供其运行。这段程序不一定是进程所专有,可以与其他进程一起使用;

  2)有起码的“私有财产”,这就是进程专用的系统堆栈空间;

  3)有“身份证”,也就是task_struct结构,也称之为“进程控制块”(PCB)。有了这个数据结构,进程才能成为内核调度的一个基本单位接受内核的调度。同时,这个结构又是进程的“财产登记卡”,记录着进程占用的各项资源。

  4)有独立的存储空间,意味着拥有专有的用户空间;还意味着除前述的系统空间堆栈外还有其专有的用户空间堆栈。(PS:进程的系统空间是不能独立的,除了各进程独有的系统堆栈空间外,任何进程都不可能直接改变用户空间的内容)。

  以上条件是必要条件,缺少其中一条,都不能称其为“进程”。如果只缺第四条,那就称为“线程”。

  在linux系统中,“进程”和“任务”是同一个意思,在内核的代码中常混用这两个名词和概念。例如每个进程都要有一个task_struct数据结构,而其号码却又是pid、唤醒一个睡眠进程的函数名为wake_up_process()。

  之所以有这样的情况是因为,linux源自Unix和i386系统结构,而unix中的进程在Intel的技术资料中称为“任务”,严格来说有点区别,但是对于系统的实现来说是一回事。

2.task_struct的定义

  操作系统通过一个称作PCB(Process Control Block,进程控制块)的数据结构管理一个进程,也称为tesk_struct结构体,这个结构体包含了一个进程所需的所有信息。它定义在linux-2.6.38.8/include/linux/sched.h文件中。

  除了最起码的“财产”,即task_struct数据结构和系统堆栈之外,一个进程还要有一些附加的资源。例如,进程拥有堵路的存储空间,就要有用于虚拟内存管理的mm_struct数据结构以及附属的vm_area数据结构,以及相应的页面目录项和页面表,

  但这些都从属于task_struct资源。task_struct数据结构在这方面相当于登记卡的作用,其具体结构源代码如下:

struct task_struct
{
/*
* offsets of these are hardcoded elsewhere - touch with care
*/
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
unsigned long flags; /* per process flags, defined below */
int sigpending;
mm_segment_t addr_limit; /* thread address space:
0-0xBFFFFFFF for user-thead
0-0xFFFFFFFF for kernel-thread
*/
struct exec_domain *exec_domain;
volatile long need_resched;
unsigned long ptrace;
int lock_depth; /* Lock depth */ /*
* offset 32 begins here on 32-bit platforms. We keep
* all fields in a single cacheline that are needed for
* the goodness() loop in schedule().
*/
long counter;
long nice;
unsigned long policy;
struct mm_struct *mm;
int has_cpu, processor;
unsigned long cpus_allowed; struct list_head run_list;
unsigned long sleep_time; struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
/* task state */
struct linux_binfmt *binfmt;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */ unsigned long personality;
int dumpable:;
int did_exec:;
pid_t pid;
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
pid_t tgid;
/* boolean value for session group leader */
int leader;
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
struct list_head thread_group;
/* PID hash table linkage. */
struct task_struct *pidhash_next;
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; /* for wait4() */
struct semaphore *vfork_sem; /* for vfork() */
unsigned long rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:;
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups;
gid_t groups[NGROUPS];
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:;
struct user_struct *user;
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[];
/* file system info */
int link_count;
struct tty_struct *tty; /* NULL if no tty */
unsigned int locks; /* How many file locks are being held */
/* ipc stuff */
struct sem_undo *semundo;
struct sem_queue *semsleeping;
/* CPU-specific state of this task */
struct thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* signal handlers */
spinlock_t sigmask_lock; /* Protects signal and blocked */
struct signal_struct *sig; sigset_t blocked;
struct sigpending pending; unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask; /* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty */
spinlock_t alloc_lock;
};

下面对结构中几个重要的成分做介绍:

  1)state(第6行)

  该变量表示进程当前运行的状态,具体定义如下:

1 #define TASK_RUNNING              0
2 #define TASK_INTERRUPTIBLE 1
3 #define TASK_UNINTERRUPTIBLE 2
4 #define TASK_ZOMBIE 4 //僵尸进程
5 #define TASK_STOPPED 8

  状态TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE均表示进程处于睡眠状态。但是TASK_UNINTERRUPTIBLE表示进程处于“深度睡眠”,而不受“信号”(signal,也称软中断)的打扰,而TASK_INTERRUPTIBLE则可以因信号的到来而被唤醒。内核中提供了不同的函数,让一个进程进入不同深度的睡眠或将进程从睡眠中唤醒。具体地说,函数sleep_on()和wake_up()用于深度睡眠,而interruptible_sleep_on()和wake_up_interruptible()则用于浅度睡眠。深度睡眠一般只用于临界区和关键性的部位,而“可中断”的睡眠那就是通用的了。特别地,当进程在“阻塞性”的系统调用中等待某一事件发生时,应该进入可中断睡眠,否则就不能对别的中断做出反应,别的进程就不能通过发一个信号来“杀掉”这个进程了。

  TASK_RUNNING状态并不是表示一个进程正在执行中,或者说这个进程就是“当前进程”,而是表示这个进程可以被调度执行而成为当前进程。当进程处于这样的可执行(或就绪)状态时,内核就将该进程的task_struct结构通过其队列头(见第30行)挂入一个“运行队列”。

  TASK_ZOMBIE状态表示进程已经“去世”而户口尚未注销。

  TASK_STOPPED主要用于调试的目的,进程接收到 一个SIGSTOP信号后就将运行状态改成     TASK_STOPPED而进入“挂起”状态,然后在接收到SIGCONT信号时又恢复继续运行。

  2)flags(第7行)

  flags反应进程状态相关信息,但并不是运行状态,而是与管理有关的其他信息。

 1 #define PF_ALIGNWARN        0x00000001      /*print alignment warning msgs*/
2 #define PF_STARTING 0x00000002 /*being created*/
3 #define PF_EXITING 0x00000004 /*getting shut down*/
4 #define PF_FORKNOEXEC 0x00000040 /*forked but did not exec*/
5 #define PF_SUPERPRIV 0x00000100 /*uses super-user privileges*/
6 #define PF_DUMPCORE 0x00000200 /*dumped core*/
7 #define PF_SIGNALED 0x00000400 /*killed by signal*/
8 #define PF_MEMALLOC 0x00000800 /*Allocating memory*/
9 #define PF_VFORK 0x00001000 /*wake up parent in mm_release*/
10 #define PF_USEDFPU 0x00100000 /*task used FPU this quantum(SMP)*/

  3)sigpending(第8行)

  表示进程收到了“信号”但是尚未处理。

  4)counter(第23行)

  与进程调度有关

  5)add_limit

  虚拟地址空间的上限,对进程而言是其用户空间的上限,所以是0xbfff ffff;对内核线程而言则是系统空间额的上限,所以是0xffff ffff

  6)binfnt

  应用程序的文件格式。

  7)pgrp,session,leader

  当一个用户登录时,就开始了一个进程组(session),此后创建的进程都属于这同一个session。

  8)user

  指向一个user_struct结构,该数据结构代表进程所属的用户。

  9)rlim

  这是一个结构数组,表明进程岁各种资源的使用数量所受的限制。

3.task_struct如何在linux中被管理

  task_struct可以以三种方式被管理,他们分别是:树,哈希表和链表,具体如下图,其中圆代表一个个进程的task_struct。

linux进程管理之概念(一)的更多相关文章

  1. Linux进程管理(一、 基本概念和数据结构)

    被问到两个问题, 后来想了下如果要讲明白还不太容易,需要对进程的概念,进程管理有清晰的认识: 1. 父进程打开了一个文件,然后通过fork创建一个子进程, 子进程是否共享父进程的文件描述符? 2. 在 ...

  2. Linux进程管理子系统分析【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51298732 Linux进程管理: 进程与程序: 程序:存放在磁盘上的一系列代码 ...

  3. Linux进程管理 (2)CFS调度器

    关键词: 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 Linux进程管理 ( ...

  4. Linux进程管理与调度-之-目录导航【转】

    转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http:// ...

  5. [转帖]linux进程管理总结

    linux进程管理总结 https://www.cnblogs.com/chenfangzhi/p/10660355.html 高手总结的.. 看出来我是菜逼. 目录 一.进程相关的概念 二.关闭会话 ...

  6. 12个Linux进程管理命令介绍(转)

    12个Linux进程管理命令介绍 [日期:2015-06-02] 来源:Linux中国  作者:Linux [字体:大 中 小]   执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的 ...

  7. Linux进程管理知识整理

    Linux进程管理知识整理 1.进程有哪些状态?什么是进程的可中断等待状态?进程退出后为什么要等待调度器删除其task_struct结构?进程的退出状态有哪些? TASK_RUNNING(可运行状态) ...

  8. Linux性能及调优指南(翻译)之Linux进程管理

    本文为IBM RedBook的Linux Performanceand Tuning Guidelines的1.1节的翻译原文地址:http://www.redbooks.ibm.com/redpap ...

  9. Linux进程管理专题

    Linux进程管理 (1)进程的诞生介绍了如何表示进程?进程的生命周期.进程的创建等等? Linux支持多种调度器(deadline/realtime/cfs/idle),其中CFS调度器最常见.Li ...

随机推荐

  1. C语言基本语法——预处理器和预处理指令

    1.什么是预处理器 2.什么是预处理器指令 3.预处理器指令 4.宏指令 5.宏函数 6.宏函数的优缺点 7.条件编译指令 1.什么是预处理器 • 预处理器是一个程序,用来处理源程序中的预处理指令. ...

  2. BZOJ 4012 [HNOI2015]开店 (树分治+二分)

    题目大意: 给你一棵树,边有边权,点有点权,有很多次询问,求点权$\in[l,r]$的所有节点到某点$x$的距离之和,强制在线 感觉这个题应该放在动态点分之前做= = 套路方法和动态点分是一样的 每次 ...

  3. JS数组中的indexOf方法

    前言 这两天在家中帮朋友做项目,项目中使用了数组的indexOf 方法,找到了一篇文章,感觉非常不错,顺便整理下以防链接丢失. 相信说到 indexOf 大家并不陌生,判断字符串是否包涵子字符串时特别 ...

  4. (转载)spring 之间的远程调用-Spring Http调用的实现

    原文:https://www.cnblogs.com/lewisat/p/6132082.html 1:Spring Http设计思想 最近在研究公司自己的一套rpc远程调用框架,看到其内部实现的设计 ...

  5. ASP.NET-优化websit

    如何优化一个网站 1.如果是数据库的问题则尝试添加索引.优化SQL语句,如果是算法的问题,则优化算法. 2.如果对于一些不经常改动的页面可以使用静态页技术! 3.对于一些数据不需要及时更新的而且取数据 ...

  6. 洛谷—— P1640 [SCOI2010]连续攻击游戏

    https://www.luogu.org/problem/show?pid=1640 题目描述 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1, ...

  7. 洛谷——P2483 [SDOI2010]魔法猪学院

    https://www.luogu.org/problem/show?pid=2483 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的 ...

  8. Android自己定义百度地图缩放图标

    自己定义实现Android百度地图的缩放图标,须要自己定义一个缩放控件,实现效果例如以下: 这里的缩放效果,实现了点击button能够对地图的放大缩小,通过手势放大与缩小也控制缩放图标的可用状态.详细 ...

  9. angular与angularjs常用指令的不同写法整理

    angularjs与angular 常用的指令写法的区别; 一:angularjs指令 1.ng-bind 使用给定的变量或表达式的值来替换 HTML 元素的内容 <p ng-bind=&quo ...

  10. 1. Git-2.12.0-64-bit .exe下载

    转自:https://blog.csdn.net/u011164906/article/details/59129835 之前一直用SVN最近接触git,Git-2.12.0-64-bit .exe文 ...