设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

操作系统中进程简介

2015-1-27 16:02| 发布者: joejoe0332| 查看: 2708| 评论: 0|原作者: 进林|来自: 伯乐在线

摘要: 很久前我就想写这篇文章了,但总是以各种理由来拖延。操作系统是我日常工作的主要部分,特别是GNU/Linux,这篇文章主要关注GUN/Linux。进程是个大话题,我不确定如何才能覆盖进程的所有知识点。这篇文章将会包含足够 ...

操作系统:进程介绍

  很久前我就想写这篇文章了,但总是以各种理由来拖延。操作系统是我日常工作的主要部分,特别是GNU/Linux,这篇文章主要关注GUN/Linux。

  进程是个大话题,我不确定如何才能覆盖进程的所有知识点。这篇文章将会包含足够多的代码让你学会如何与进程交互。这些代码例子将会侧重于GNU/Linux系统,因为这是我最熟悉的系统。

  那么,什么是进程呢?Linux信息项目(The Linux Information)把进程定义为“程序的一个执行(即,运行)实例”。所以,要定义进程我们先要定义什么是程序。再次根据Linux信息项目里的定义,“程序是内存里的一个可执行文件。”

  所以,我们知道进程是正在运行的程序的一部分。这是否意味着进程一定是在运行中的?不一定。


进程状态

  为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。

  下面的状态在 fs/proc/array.c 文件里定义:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

  运行状态(running)并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。睡眠状态(sleeping)意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

  可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT信号让进程继续运行。

  例如,可以用下面的方法来停止或继续运行进程:

kill -SIGSTOP <pid>
kill -SIGCONT <pid>

  可以使用gdb终止进程来实现跟踪终止状态。如果我没有记错的话,这个状态和终止状态基本上是一样的。

  死亡状态是内核运行 kernel/exit.c 里的 do_exit() 函数返回的状态。这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

  僵死状态(Zombies)是一个比较特殊的状态。有些人认为这个状态是在父进程死亡而子进程存活时产生的。实际上不是这样的。父进程可能已经死了但子进程依然存活着,那个子进程的父进程将会成为init进程,pid 1。当进程退出并且父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵死进程。僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

  这里有一个创建维持30秒的僵死进程例子:

#include <stdio.h>
#include <stdlib.h>
 
/*
* A program to create a 30s zombie
* The parent spawns a process that isn't reaped until after 30s.
* The process will be reaped after the parent is done with sleep.
*/
int main(int argc, char **argv[])
{
int id = fork();
 
if ( id > 0 ) {
printf("Parent is sleeping..n");
sleep(30);
}
 
if ( id == 0 )
printf("Child process is done.n");
 
exit(EXIT_SUCCESS);
}

Linux进程状态是一篇非常棒的文章,它使用代码例子来讲述进程状态并使用 ptrace 来控制它。


进程包含了什么信息?

  我简要地提过进程表,我将会在这解释什么是进程表。进程表是Linux内核的一种数据结构,它会被装载到RAM里并且包含着进程的信息。

  每个进程都把它的信息放在 task_struct 这个数据结构里,task_struct 包含了这些内容:

  • 状态(任务状态,退出代码,退出信号。。。)
  • 优先级
  • 进程id(PID)
  • 父进程id(PPID)
  • 子进程
  • 使用情况(cpu时间,打开的文件。。。)
  • 跟踪信息
  • 调度信息
  • 内存管理信息

  保存进程信息的数据结构叫做 task_struct,并且可以在 include/linux/sched.h 里找到它。所有运行在系统里的进程都以 task_struct 链表的形式存在内核里。

  进程的信息可以通过 /proc 系统文件夹查看。要获取PID为400的进程信息,你需要查看 /proc/400 这个文件夹。大多数进程信息同样可以使用topps这些用户级工具来获取。


进程执行

  当进程执行时,它会被装载进虚拟内存,为程序变量分配空间,并把相关信息添到task_struct里。

  进程内存布局分为四个不同的段:

  • 文本段,包含程序的源指令。
  • 数据段,包含了静态变量。
  • 堆,动态内存分区区域。
  • 栈,动态增长与收缩的段,保存本地变量。

  这里有两种创建进程的方法,fork()execve()。它们都是系统调用,但它们的运行方式有点不同。

  要创建一个子进程可以执行fork()系统调用。然后子进程会得到父进程中数据段,栈段和堆区域的一份拷贝。子进程独立可以修改这些内存段。但是文本段是父进程和子进程共享的内存段,不能被子进程修改。

  如果使用execve()创建一个新进程。这个系统调用会销毁所有的内存段去重新创建一个新的内存段。然而,execve()需要一个可执行文件或者脚本作为参数,这和fork()有所不同。

  注意,execve()fork()创建的进程都是运行进程的子进程。

  进程执行还有很多其他的内容,比如进程调度,权限许可,资源限制,库链接,内存映射… 然而这篇文章由于篇幅限制不可能都讲述,以后访问可能会加上



酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部