精华内容
下载资源
问答
  • 进程

    千次阅读 2020-10-23 08:42:09
    通过进程,Linux 安排不同的程序等待使用 CPU。 有时候,计算机变得呆滞,运行缓慢,或者一个应用程序停止响应。在这一章中,我们将看一些 可用的命令行工具,这些工具帮助我们查看程序的执行状态,以及怎样终止...

    通常,现在的操作系统都支持多任务,意味着操作系统(给用户)造成了一种假象,(让用户觉得) 它同时能够做多件事情,事实上,它是快速地轮换执行这些任务的。Linux 内核通过使用进程,来 管理多任务。通过进程,Linux 安排不同的程序等待使用 CPU。

    有时候,计算机变得呆滞,运行缓慢,或者一个应用程序停止响应。在这一章中,我们将看一些 可用的命令行工具,这些工具帮助我们查看程序的执行状态,以及怎样终止行为不当的进程。

    这一章将介绍以下命令:

    • ps – 报告当前进程快照

    • top – 显示任务

    • jobs – 列出活跃的任务

    • bg – 把一个任务放到后台执行

    • fg – 把一个任务放到前台执行

    • kill – 给一个进程发送信号

    • killall – 杀死指定名字的进程

    • shutdown – 关机或重启系统

    进程是怎样工作的

    当系统启动的时候,内核先把一些它自己的程序初始化为进程,然后运行一个叫做 init 的程序。init, 依次地,再运行一系列的称为 init 脚本的 shell 脚本(位于/etc),它们可以启动所有的系统服务。 其中许多系统服务以守护(daemon)程序的形式实现,守护程序仅在后台运行,没有任何用户接口。 这样,即使我们没有登录系统,至少系统也在忙于执行一些例行事务。

    一个程序可以发动另一个程序,这个事实在进程方案中,表述为一个父进程创建了一个子进程。

    内核维护每个进程的信息,以此来保持事情有序。例如,系统分配给每个进程一个数字,这个数字叫做 进程 ID 或 PID。PID 号按升序分配,init 进程的 PID 总是1。内核也对分配给每个进程的内存进行跟踪。 像文件一样,进程也有所有者和用户 ID,有效用户 ID,等等。

    查看进程

    查看进程,最常使用地命令(有几个命令)是 ps。ps 程序有许多选项,它最简单地使用形式是这样的:

    [me@linuxbox ~]$ ps
    PID TTY           TIME CMD
    5198 pts/1    00:00:00 bash
    10129 pts/1   00:00:00 ps
    
    

    上例中,列出了两个进程,进程 5198 和进程 10129,各自代表命令 bash 和 ps。正如我们所看到的, 默认情况下,ps 不会显示很多进程信息,只是列出与当前终端会话相关的进程。为了得到更多信息, 我们需要加上一些选项,但是在这样做之前,我们先看一下 ps 命令运行结果的其它字段。 TTY 是 “Teletype” 的简写,是指进程的控制终端。这里,Unix 展示它的年龄。TIME 字段表示 进程所消耗的 CPU 时间数量。正如我们所看到的,这两个进程使计算机工作起来很轻松。

    如果给 ps 命令加上选项,我们可以得到更多关于系统运行状态的信息:

    [me@linuxbox ~]$ ps x
    PID TTY   STAT   TIME COMMAND
    2799 ?    Ssl    0:00 /usr/libexec/bonobo-activation-server –ac
    2820 ?    Sl     0:01 /usr/libexec/evolution-data-server-1.10 --
    
    and many more...
    
    

    加上 “x” 选项(注意没有开头的 “-“ 字符),告诉 ps 命令,展示所有进程,不管它们由什么 终端(如果有的话)控制。在 TTY 一栏中出现的 “?” ,表示没有控制终端。使用这个 “x” 选项,可以 看到我们所拥有的每个进程的信息。

    因为系统中正运行着许多进程,所以 ps 命令的输出结果很长。这经常很有帮助,要是把 ps 的输出结果 管道到 less 命令,借助 less 工具,更容易浏览。一些选项组合也会产生很长的输出结果,所以最大化 终端仿真器窗口,也是一个好主意。

    输出结果中,新添加了一栏,标题为 STAT 。STAT 是 “state” 的简写,它揭示了进程当前状态:

    表11-1: 进程状态

    状态 意义
    R 运行。这意味着,进程正在运行或准备运行。
    S 正在睡眠。 进程没有运行,而是,正在等待一个事件, 比如说,一个按键或者网络数据包。
    D 不可中断睡眠。进程正在等待 I/O,比方说,一个磁盘驱动器的 I/O。
    T 已停止. 已经指示进程停止运行。稍后介绍更多。
    Z 一个死进程或“僵尸”进程。这是一个已经终止的子进程,但是它的父进程还没有清空它。 (父进程没有把子进程从进程表中删除)
    < 一个高优先级进程。这可能会授予一个进程更多重要的资源,给它更多的 CPU 时间。 进程的这种属性叫做 niceness。具有高优先级的进程据说是不好的(less nice), 因为它占用了比较多的 CPU 时间,这样就给其它进程留下很少时间。
    N 低优先级进程。 一个低优先级进程(一个“好”进程)只有当其它高优先级进程执行之后,才会得到处理器时间。

    进程状态信息之后,可能还跟随其他的字符。这表示各种外来进程的特性。详细信息请看 ps 手册页。

    另一个流行的选项组合是 “aux”(不带开头的”-“字符)。这会给我们更多信息:

    [me@linuxbox ~]$ ps aux
    USER   PID  %CPU  %MEM     VSZ    RSS  TTY   STAT   START   TIME  COMMAND
    root     1   0.0   0.0    2136    644  ?     Ss     Mar05   0:31  init
    root     2   0.0   0.0       0      0  ?     S&lt;     Mar05   0:00  [kt]
    
    and many more...
    
    

    这个选项组合,能够显示属于每个用户的进程信息。使用这个选项,可以唤醒 “BSD 风格” 的输出结果。 Linux 版本的 ps 命令,可以模拟几个不同 Unix 版本中的 ps 程序的行为。通过这些选项,我们得到 这些额外的列。

    表11-2: BSD 风格的 ps 命令列标题

    标题 意思
    USER 用户 ID. 进程的所有者。
    %CPU 以百分比表示的 CPU 使用率
    %MEM 以百分比表示的内存使用率
    VSZ 虚拟内存大小
    RSS 进程占用的物理内存的大小,以千字节为单位。
    START 进程运行的起始时间。若超过24小时,则用天表示。

    用 top 命令动态查看进程

    虽然 ps 命令能够展示许多计算机运行状态的信息,但是它只是提供,ps 命令执行时刻的机器状态快照。 为了看到更多动态的信息,我们使用 top 命令:

    [me@linuxbox ~]$ top
    
    

    top 程序连续显示系统进程更新的信息(默认情况下,每三分钟更新一次),”top”这个名字 来源于这个事实,top 程序是用来查看系统中“顶端”进程的。top 显示结果由两部分组成: 最上面是系统概要,下面是进程列表,以 CPU 的使用率排序。

    top - 14:59:20 up 6:30, 2 users, load average: 0.07, 0.02, 0.00
    Tasks: 109 total,   1 running,  106 sleeping,    0 stopped,    2 zombie
    Cpu(s): 0.7%us, 1.0%sy, 0.0%ni, 98.3%id, 0.0%wa, 0.0%hi, 0.0%si
    Mem:   319496k total,   314860k used,   4636k free,   19392k buff
    Swap:  875500k total,   149128k used,   726372k free,  114676k cach
    
     PID  USER       PR   NI   VIRT   RES   SHR  S %CPU  %MEM   TIME+    COMMAND
    6244  me         39   19  31752  3124  2188  S  6.3   1.0   16:24.42 trackerd
    ....
    
    

    其中系统概要包含许多有用信息。下表是对系统概要的说明:

    表11-3: top 命令信息字段

    行号 字段 意义
    1 top 程序名。
    14:59:20 当前时间。  
    up 6:30 这是正常运行时间。它是计算机从上次启动到现在所运行的时间。 在这个例子里,系统已经运行了六个半小时。  
    2 users 有两个用户登录系统。  
    load average: 加载平均值是指,等待运行的进程数目,也就是说,处于运行状态的进程个数, 这些进程共享 CPU。展示了三个数值,每个数值对应不同的时间周期。第一个是最后60秒的平均值, 下一个是前5分钟的平均值,最后一个是前15分钟的平均值。若平均值低于1.0,则指示计算机 工作不忙碌。  
    2 Tasks: 总结了进程数目和各种进程状态。
    3 Cpu(s): 这一行描述了 CPU 正在执行的进程的特性。
    0.7%us 0.7% of the CPU is being used for user processes. 这意味着进程在内核之外。  
    1.0%sy 1.0%的 CPU 时间被用于系统(内核)进程。  
    0.0%ni 0.0%的 CPU 时间被用于"nice"(低优先级)进程。  
    98.3%id 98.3%的 CPU 时间是空闲的。  
    0.0%wa 0.0%的 CPU 时间来等待 I/O。  
    4 Mem: 展示物理内存的使用情况。
    5 Swap: 展示交换分区(虚拟内存)的使用情况。

    top 程序接受一系列从键盘输入的命令。两个最有趣的命令是 h 和 q。h,显示程序的帮助屏幕,q, 退出 top 程序。

    两个主要的桌面环境都提供了图形化应用程序,来显示与 top 程序相似的信息 (和 Windows 中的任务管理器差别不多),但是我觉得 top 程序要好于图形化的版本, 因为它运行速度快,并且消费很少的系统资源。毕竟,我们的系统监测程序不能成为 系统怠工的源泉,而这是我们试图追踪的信息。

    控制进程

    现在我们可以看到和监测进程,然后得到一些对它们的控制权。为了我们的实验,我们将使用 一个叫做 xlogo 的小程序,作为我们的实验品。这个 xlogo 程序是 X 窗口系统 (底层引擎使图形界面显示在屏幕上)提供的实例程序,这个实例简单地显示一个大小可调的 包含 X 标志的窗口。首先,我们需要知道测试的主题:

    [me@linuxbox ~]$ xlogo
    
    

    命令执行之后,一个包含 X 标志的小窗口应该出现在屏幕的某个位置上。在一些系统中,xlogo 命令 会打印一条警告信息,但是不用理会它。

    小贴士:如果你的系统不包含 xlogo 程序,试着用 gedit 或者 kwrite 来代替。

    通过调整它的窗口大小,我们能够证明 xlogo 程序正在运行。如果这个标志以新的尺寸被重画, 则这个程序正在运行。

    注意,为什么我们的 shell 提示符还没有返回?这是因为 shell 正在等待这个程序结束, 就像到目前为止我们用过的其它所有程序一样。如果我们关闭 xlogo 窗口,shell 提示符就返回了。

    中断一个进程

    我们再运行 xlogo 程序一次,观察一下发生了什么事。首先,执行 xlogo 命令,并且 证实这个程序正在运行。下一步,回到终端窗口,按下 Ctrl-c。

    [me@linuxbox ~]$ xlogo
    [me@linuxbox ~]$
    
    

    在一个终端中,输入 Ctrl-c,中断一个程序。这意味着,我们礼貌地要求终止这个程序。 输入 Ctrl-c 之后,xlogo 窗口关闭,shell 提示符返回。

    通过这个技巧,许多(但不是全部)命令行程序可以被中断。

    把一个进程放置到后台(执行)

    比方说,我们想让 shell 提示符返回,却没有终止 xlogo 程序。为达到这个目的,我们把 这个程序放到后台执行。把终端看作是一个有前台(表层放置可见的事物,像 shell 提示符) 和后台(表层之下放置隐藏的事物)(的设备)。启动一个程序,让它立即在后台 运行,我们在程序命令之后,加上”&”字符:

    [me@linuxbox ~]$ xlogo &
    [1] 28236
    [me@linuxbox ~]$
    
    

    执行命令之后,这个 xlogo 窗口出现,并且 shell 提示符返回,同时打印一些有趣的数字。 这条信息是 shell 特性的一部分,叫做工作控制。通过这条信息,shell 告诉我们,已经启动了 工作号为1(“[1]”),PID 为28236的程序。如果我们运行 ps 命令,可以看到我们的进程:

    [me@linuxbox ~]$ ps
      PID TTY         TIME   CMD
    10603 pts/1   00:00:00   bash
    28236 pts/1   00:00:00   xlogo
    28239 pts/1   00:00:00   ps
    
    

    工作控制,这个 shell 功能可以列出从终端中启动的任务。执行 jobs 命令,我们可以看到这个输出列表:

    [me@linuxbox ~]$ jobs
    [1]+ Running            xlogo &
    
    

    结果显示我们有一个任务,编号为“1”,它正在运行,并且这个任务的命令是 xlogo &。

    进程返回到前台

    一个在后台运行的进程对一切来自键盘的输入都免疫,也不能用 Ctrl-c 来中断它。使用 fg 命令,让一个进程返回前台执行:

    [me@linuxbox ~]$ jobs
    [1]+ Running        xlogo &
    [me@linuxbox ~]$ fg %1
    xlogo
    
    

    fg 命令之后,跟随着一个百分号和工作序号(叫做 jobspec)。如果我们只有一个后台任务,那么 jobspec 是可有可无的。输入 Ctrl-c 来终止 xlogo 程序。

    停止一个进程

    有时候,我们想要停止一个进程,而没有终止它。这样会把一个前台进程移到后台等待。 输入 Ctrl-z,可以停止一个前台进程。让我们试一下。在命令提示符下,执行 xlogo 命令, 然后输入 Ctrl-z:

    [me@linuxbox ~]$ xlogo
    [1]+ Stopped                 xlogo
    [me@linuxbox ~]$
    
    

    停止 xlogo 程序之后,通过调整 xlogo 的窗口大小,我们可以证实这个程序已经停止了。 它看起来像死掉了一样。使用 fg 命令,可以恢复程序到前台运行,或者用 bg 命令把程序移到后台。

    [me@linuxbox ~]$ bg %1
    [1]+ xlogo &
    [me@linuxbox ~]$
    
    

    和 fg 命令一样,如果只有一个任务的话,jobspec 参数是可选的。

    因为把一个进程从前台移到后台很方便,如果我们从命令行启动一个图形界面的程序,但是 忘记把它放到后台执行,即没有在命令后加上字符”&”,(也不用担心)。

    为什么要从命令行启动一个图形界面程序呢?有两个原因。第一个,你想要启动的程序,可能 没有在窗口管理器的菜单中列出来(比方说 xlogo)。第二个,从命令行启动一个程序, 你能够看到一些错误信息,如果从窗口系统中运行程序的话,这些信息是不可见的。有时候, 一个程序不能从图形界面菜单中启动。这时候,应该从命令行中启动它。我们可能会看到 错误信息,这些信息揭示了问题所在。一些图形界面程序还有许多有意思并且有用的命令行选项。

    Signals

    kill 命令被用来“杀死”程序。这样我们就可以终止需要杀死的程序。这里有一个实例:

    [me@linuxbox ~]$ xlogo &
    [1] 28401
    [me@linuxbox ~]$ kill 28401
    [1]+ Terminated               xlogo
    
    

    首先,我们在后台启动 xlogo 程序。shell 打印出 jobspec 和这个后台进程的 PID。下一步,我们使用 kill 命令,并且指定我们想要终止的进程 PID。也可以用 jobspec(例如,“%1”)来代替 PID。

    虽然这个命令很直接了当,但不仅仅这些。这个 kill 命令不是确切地“杀死”程序,而是给程序 发送信号。信号是操作系统与程序之间进行通信,所采用的几种方式中的一种。我们已经看到 信号,在使用 Ctrl-c 和 Ctrl-z 的过程中。当终端接受了其中一个按键组合后,它会给在前端运行 的程序发送一个信号。在使用 Ctrl-c 的情况下,会发送一个叫做 INT(中断)的信号;当使用 Ctrl-z 时,则发送一个叫做 TSTP(终端停止)的信号。程序,反过来,倾听信号的到来,当程序 接到信号之后,则做出响应。一个程序能够倾听和响应信号,这个事实允许一个程序做些事情, 比如,当程序接到一个终止信号时,它可以保存所做的工作。

    通过 kill 命令给进程发送信号

    kill 命令被用来给程序发送信号。它最常见的语法形式看起来像这样:

    kill [-signal] PID...
    
    

    如果在命令行中没有指定信号,那么默认情况下,发送 TERM(终止)信号。kill 命令被经常 用来发送以下命令:

    表 11-4: 常用信号
    | 编号 | 名字 | 含义 |
    | 1 | HUP | 挂起。这是美好往昔的痕迹,那时候终端机通过电话线和调制解调器连接到 远端的计算机。这个信号被用来告诉程序,控制的终端机已经“挂起”。 通过关闭一个终端会话,可以说明这个信号的作用。发送这个信号到终端机上的前台程序,程序会终止。

    许多守护进程也使用这个信号,来重新初始化。这意味着,当发送这个信号到一个守护进程后, 这个进程会重新启动,并且重新读取它的配置文件。Apache 网络服务器守护进程就是一个例子。

    |
    | 2 | INT | 中断。实现和 Ctrl-c 一样的功能,由终端发送。通常,它会终止一个程序。 |
    | 9 | KILL | 杀死。这个信号很特别。鉴于进程可能会选择不同的方式,来处理发送给它的 信号,其中也包含忽略信号,这样呢,从不发送 Kill 信号到目标进程。而是内核立即终止 这个进程。当一个进程以这种方式终止的时候,它没有机会去做些“清理”工作,或者是保存劳动成果。 因为这个原因,把 KILL 信号看作杀手锏,当其它终止信号失败后,再使用它。 |
    | 15 | TERM | 终止。这是 kill 命令发送的默认信号。如果程序仍然“活着”,可以接受信号,那么 这个信号终止。 |
    | 18 | CONT | 继续。在停止一段时间后,进程恢复运行。 |
    | 19 | STOP | 停止。这个信号导致进程停止运行,而没有终止。像 KILL 信号,它不被 发送到目标进程,因此它不能被忽略。 |

    让我们实验一下 kill 命令:

    [me@linuxbox ~]$ xlogo &
    [1] 13546
    [me@linuxbox ~]$ kill -1 13546
    [1]+ Hangup         xlogo
    
    

    在这个例子里,我们在后台启动 xlogo 程序,然后通过 kill 命令,发送给它一个 HUP 信号。 这个 xlogo 程序终止运行,并且 shell 指示这个后台进程已经接受了一个挂起信号。在看到这条 信息之前,你可能需要多按几次 enter 键。注意,既可以用号码,也可以用名字,不过要在名字前面 加上字母“SIG”,来指定所要发送的信号。

    [me@linuxbox ~]$ xlogo &
    [1] 13546
    [me@linuxbox ~]$ kill -1 13546
    [1]+ Hangup                    xlogo
    
    

    重复上面的例子,试着使用其它的信号。记住,你也可以用 jobspecs 来代替 PID。

    进程,和文件一样,拥有所有者,所以为了能够通过 kill 命令来给进程发送信号, 你必须是进程的所有者(或者是超级用户)。

    除了上表列出的 kill 命令最常使用的信号之外,还有一些系统频繁使用的信号。以下是其它一些常用 信号列表:

    表 11-5: 其它常用信号
    | 编号 | 名字 | 含义 |
    | 3 | QUIT | 退出 |
    | 11 | SEGV | 段错误。如果一个程序非法使用内存,就会发送这个信号。也就是说, 程序试图写入内存,而这个内存空间是不允许此程序写入的。 |
    | 20 | TSTP | 终端停止。当按下 Ctrl-z 组合键后,终端发送这个信号。不像 STOP 信号, TSTP 信号由目标进程接收,且可能被忽略。 |
    | 28 | WINCH | 改变窗口大小。当改变窗口大小时,系统会发送这个信号。 一些程序,像 top 和 less 程序会响应这个信号,按照新窗口的尺寸,刷新显示的内容。 |

    为了满足读者的好奇心,通过下面的命令可以得到一个完整的信号列表:

    [me@linuxbox ~]$ kill -l
    
    

    通过 killall 命令给多个进程发送信号

    也有可能通过 killall 命令,给匹配特定程序或用户名的多个进程发送信号。下面是 killall 命令的语法形式:

    killall [-u user] [-signal] name...
    
    

    为了说明情况,我们将启动一对 xlogo 程序的实例,然后再终止它们:

    [me@linuxbox ~]$ xlogo &
    [1] 18801
    [me@linuxbox ~]$ xlogo &
    [2] 18802
    [me@linuxbox ~]$ killall xlogo
    [1]- Terminated                xlogo
    [2]+ Terminated                xlogo
    
    

    记住,和 kill 命令一样,你必须拥有超级用户权限才能给不属于你的进程发送信号。

    更多和进程相关的命令

    因为监测进程是一个很重要的系统管理任务,所以有许多命令与它相关。玩玩下面几个命令:

    表11-6: 其它与进程相关的命令
    | 命令名 | 命令描述 |
    | pstree | 输出一个树型结构的进程列表,这个列表展示了进程间父/子关系。 |
    | vmstat | 输出一个系统资源使用快照,包括内存,交换分区和磁盘 I/O。 为了看到连续的显示结果,则在命令名后加上延时的时间(以秒为单位)。例如,“vmstat 5”。 终止输出,按下 Ctrl-c 组合键。 |
    | xload | 一个图形界面程序,可以画出系统负载的图形。 |
    | tload | 与 xload 程序相似,但是在终端中画出图形。使用 Ctrl-c,来终止输出。

    展开全文
  • Linux内核本身和进程的区别 内核线程、用户进程、用户线程 这个概念是很多人都混淆的了,我也是,刚开始无法理解OS时,把Linux内核也当做一个进程。 其实内核本身不是以进程形式存在的,最多在初始化的过程中...

    Linux内核本身和进程的区别 内核线程、用户进程、用户线程

    这个概念是很多人都混淆的了,我也是,刚开始无法理解OS时,把Linux内核也当做一个进程。
    其实内核本身不是以进程形式存在的,最多在初始化的过程中表现得就像一个进程,但是内核绝对没有进程的数据结构task_struct,可以严格跟进程区分开 。自从创建init 进程之后,内核就不再主动占有cpu了。只有当进程主动要求和中断到来时,内核才动一动,很快又把cpu还给合适的进程,不是想象中的,以后台服务进程的形式存在。

    Linux上进程分3种,内核线程(或者叫核心进程)、用户进程、用户线程

    内核线程拥有 进程描述符、PID、进程正文段、核心堆栈
    当和用户进程拥有相同的static_prio 时,内核线程有机会得到更多的cpu资源
    内核线程的bug直接影响内核,很容易搞死整个系统
    内核线程不需要访问用户空间内存,这是再好不过了。所以内核线程的task_struct 的mm域为空
    但是刚才说过,内核线程还有核心堆栈,没有mm怎么访问它的核心堆栈呢?这个核心堆栈跟task_struct的
    thread_info共享8k的空间,所以不用mm描述。
    但是内核线程总要访问内核空间的其他内核啊,没有mm域毕竟是不行的。
    所以内核线程被调用时,内核会将其task_strcut 的active_mm指向前一个被调度出的进程的mm域
    ,在需要的时候,内核线程可以使用前一个进程的内存描述符。
    因为内核线程不访问用户空间,只操作内核空间内存,而所有进程的内核空间都是一样的。这样就省下了一个mm域的内存。

    用户进程拥有 进程描述符、PID、进程正文段、核心堆栈 、用户空间的数据段和堆栈

    用户线程拥有 进程描述符、PID、进程正文段、核心堆栈,同父进程共享用户空间的数据段和堆栈
    用户线程也可以通过exec函数族拥有自己的用户空间的数据段和堆栈,成为用户进程。


    前言:

    从内核的角度来说,它并没有线程这个概念。Linux把所有线程都当做进程来实现。内核并没有准备特别的调度算法或者定义特别的数据结构来表示线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯一属于自己的task_struct,所以在内核中,它看起来就像是一个普通的进程(只是该进程和其他一些进程共享某些资源,如地址空间

    一.内核线程

    1.内核经常需要在后台执行一些操作。这种任务可以通过内核线程 (kernel thread)完成。

    2.内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,(实际它的mm指针被设置为NULL)

    3.内核线程只在内核空间运行,从来不切换到用户空间去。内核进程和 普通进程一样,可以被调度,也可以被抢占

    4.内核线程也只能由其他内核线程创建。在现有内核线程中创建一个新的内核线程的方法如下:

    intkernel_thread(int (*fn)(void *),void *arg, unsigned long flags)

    新的任务也是通过向普通的clone()系统调用传递特定的flags参数而创建的。在上面的函数返回时,父线程退出,并返回一个指向子线程task_struct的指针。子线程开始运行fn指向的函数,arg是运行时需要用到的参数。

    5.一般情况下,内核线程会将它在创建时得到的函数永远执行下去(除非系统重启)。改函数通常由一个循环构成,在需要的时候,这个内核线程就会被唤醒和执行吗,完成了当前任务,它会自行休眠。

    展开全文
  • 我们经常提到线程、线程组、内核进程、用户进程、轻量级进程等词汇,那么他们之间有什么区别和联系呢? 首先,我们需要明确一点,Linux下并没有真正意义上的线程,甚至可以说没有进程这个概念,Linux下只有task,其...

    区别和联系

    我们经常提到线程、线程组、内核进程、用户进程、轻量级进程等词汇,那么他们之间有什么区别和联系呢?

    首先,我们需要明确一点,Linux下并没有真正意义上的线程,甚至可以说没有进程这个概念,Linux下只有task,其对应的数据结构为task_struct,这里为了方便说明以及按照比较主流的说法,我们将task称之为进程。

    对于一个进程来说,它一定是运行在内存的某个连续或不连续的区域,先以用户进程为例。

    用户进程和内核进程

    对于Linux来说,有两个概念叫做内核空间和用户空间,以32位x86架构的Linux为例,Linux的虚拟地址空间为4GB,其中前1GB称为内核空间,后3GB称为用户空间,进程运行在内核空间时称为内核态,运行在用户空间称之为用户态。对于用户态进程来说,出于程序设计方便和内存安全的角度等原因,为每个用户态进程引入了独立的虚拟地址空间,其被映射到用户空间。

    用户进程,平时运行在用户态,有自己的虚拟地址空间,但是可以通过中断、系统调用等内陷到内核态。
    内核进程,没有独立的地址空间,所有内核线程的地址空间都是一样的,没有自己的地址空间,所以它们的”current->mm”都为空,其运行在内核空间,本身就是内核的一部分或者说是内核的分身。

    线程、轻量级进程、线程组和用户进程

    我们开始说到,linux下没有真正意义上的线程,那么linux下的线程是什么呢?

    我们说过Linux下只有task,对应的数据结构为task_struct,task_strcut中就包含了task所拥有的各种资源,如果一个运行在用户空间的task独占task_struct的所有资源,我们说它是一个用户进程,当若干个task要共享资源时,我们把这些task称之为LWP(轻量级线程)。

    Linux的线程只是共享了资源的进程,所以在Linux下,线程其实就是LWP,而那些共享了资源的task组合在一起,我们称之为线程组。

    即对于普通的用户进程,我们可以认为是只有一个LWP的线程组,但对于一个有着多线程的进程(线程组),其中的每一个线程都是LWP,组内共享资源。在一个普通进程内创建线程时,就是在线程组内增加LWP。

    进程的创建

    在Linux下,有着这几个创建进程(task)的函数:
    fork
    vfork
    clone
    pthread_create
    kernel_thread
    所有的这些函数,最终都是在调用do_fork(),只是传入的参数不同

    1. fork(sys_fork)在调用do_fork()时,clone_flags没有置位任何clone标志位,即创建的进程不共享任何数据。
    2. vfork(sys_vfork)在调用do_fork()时,置为了CLONE_VFORK CLONE_VM,即共享VM,以及当mm_release时子进程唤醒父进程
    3. clone(sys_clone)本身只进行clone_flags的传递
    4. pthread_create 则将CLONE_VM CLONE_FS CLONE_FILES CLONE_SIGHAND等标志位置位,即共享VM,共享fs info,共享打开的文件,共享信号句柄和阻塞的信号? 即除了栈是独立的,其他都是共享的,所以在linux中,线程仅仅是一个使用共享资源的轻量级进程
    5. kernel_thread 在传递的参数基础上增加了CLONE_VM和CLONE_UNTRACED。
    • kernel_thread 只能由内核进程调用,创建的进程没有独立虚拟地址空间,只能运行在内核空间,为内核进程。
    • fork,创建的进程与父进程不共享资源,而是写时复制,故而创建的是用户进程
    • vfork,带有CLONE_VM标志位,故而创建的是LWP
    • pthread_create,共享各类资源,创建的也是LWP

    关于fork vfork clone pthread_create kernel_thread 以及 do_fork更进一步的细节,先挖个坑,以后再填

    展开全文
  • 内核线程 内核线程只运行在内核态,不受用户态上下文的拖累。 处理器竞争:可以在全系统范围内竞争处理器资源;...轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象
    
    

    内核线程

    内核线程只运行在内核态,不受用户态上下文的拖累。

    • 处理器竞争:可以在全系统范围内竞争处理器资源;
    • 使用资源:唯一使用的资源是内核栈和上下文切换时保持寄存器的空间
    • 调度:调度的开销可能和进程自身差不多昂贵
    • 同步效率:资源的同步和数据共享比整个进程的数据同步和共享要低一些。

    轻量级进程(vfork创建)

    轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。内核线程只能由内核管理并像普通进程一样被调度。

    轻量级进程由clone()系统调用创建,参数是CLONE_VM,即与父进程是共享进程地址空间和系统资源。

    与普通进程区别:LWP只有一个最小的执行上下文和调度程序所需的统计信息。

    • 处理器竞争:因与特定内核线程关联,因此可以在全系统范围内竞争处理器资源
    • 使用资源:与父进程共享进程地址空间
    • 调度:像普通进程一样调度

    用户线程

    用户线程是完全建立在用户空间的线程库,用户线程的创建、调度、同步和销毁全又库函数在用户空间完成,不需要内核的帮助。因此这种线程是极其低消耗和高效的。

    • 处理器竞争:单纯的用户线程是建立在用户空间,其对内核是透明的,因此其所属进程单独参与处理器的竞争,而进程的所有线程参与竞争该进程的资源。
    • 使用资源:与所属进程共享进程地址空间和系统资源。
    • 调度:由在用户空间实现的线程库,在所属进程内进行调度

    Linux使用的线程库

    LinuxThreads是用户空间的线程库,所采用的是线程-进程1对1模型(即一个用户线程对应一个轻量级进程,而一个轻量级进程对应一个特定 的内核线程),将线程的调度等同于进程的调度,调度交由内核完成,而线程的创建、同步、销毁由核外线程库完成(LinuxThtreads已绑定到 GLIBC中发行)。

    在LinuxThreads中,由专门的一个管理线程处理所有的线程管理工作。当进程第一次调用pthread_create()创建线程时就会先 创建(clone())并启动管理线程。后续进程pthread_create()创建线程时,都是管理线程作为pthread_create()的调用 者的子线程,通过调用clone()来创建用户线程,并记录轻量级进程号和线程id的映射关系,因此,用户线程其实是管理线程的子线程。

    LinuxThreads只支持调度范围为PTHREAD_SCOPE_SYSTEM的调度,默认的调度策略是SCHED_OTHER。

    用户线程调度策略也可修改成SCHED_FIFO或SCHED_RR方式,这两种方式支持优先级为0-99,而SCHED_OTHER只支持0。

    • SCHED_OTHER 分时调度策略,
    • SCHED_FIFO   实时调度策略,先到先服务
    • SCHED_RR     实时调度策略,时间片轮转

    SCHED_OTHER是普通进程的,后两个是实时进程的(一般的进程都是普通进程,系统中出现实时进程的机会很少)。SCHED_FIFO、 SCHED_RR优先级高于所有SCHED_OTHER的进程,所以只要他们能够运行,在他们运行完之前,所有SCHED_OTHER的进程的都没有得到 执行的机会。

    附: 基础知识(线程和进程)

    按照教科书上的定义,进程是资源管理的最小单位,线程是程序执行的最小单位。在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持SMP以及减小(进程/线程)上下文切换开销。

    无论按照怎样的分法,一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等),而将线程分配到某个cpu上执 行。一个进程当然可以拥有多个线程,此时,如果进程运行在SMP机器上,它就可以同时使用多个cpu来执行各个线程,达到最大程度的并行,以提高效率;同 时,即使是在单cpu的机器上,采用多线程模型来设计程序,正如当年采用多进程模型代替单进程模型一样,使设计更简洁、功能更完备,程序的执行效率也更 高,例如采用多个线程响应多个输入,而此时多线程模型所实现的功能实际上也可以用多进程模型来实现,而与后者相比,线程的上下文切换开销就比进程要小多 了,从语义上来说,同时响应多个输入这样的功能,实际上就是共享了除cpu以外的所有资源的。

    针对线程模型的两大意义,分别开发出了核心级线程和用户级线程两种线程模型,分类的标准主要是线程的调度者在核内还是在核外。前者更利于并发使用多 处理器的资源,而后者则更多考虑的是上下文切换开销。在目前的商用系统中,通常都将两者结合起来使用,既提供核心线程以满足smp系统的需要,也支持用线 程库的方式在用户态实现另一套线程机制,此时一个核心线程同时成为多个用户态线程的调度者。正如很多技术一样,”混合”通常都能带来更高的效率,但同时也 带来更大的实现难度,出于”简单”的设计思路,Linux从一开始就没有实现混合模型的计划,但它在实现上采用了另一种思路的”混合”。

    在线程机制的具体实现上,可以在操作系统内核上实现线程,也可以在核外实现,后者显然要求核内至少实现了进程,而前者则一般要求在核内同时也支持进 程。核心级线程模型显然要求前者的支持,而用户级线程模型则不一定基于后者实现。这种差异,正如前所述,是两种分类方式的标准不同带来的。

    当核内既支持进程也支持线程时,就可以实现线程-进程的”多对多”模型,即一个进程的某个线程由核内调度,而同时它也可以作为用户级线程池的调度 者,选择合适的用户级线程在其空间中运行。这就是前面提到的”混合”线程模型,既可满足多处理机系统的需要,也可以最大限度的减小调度开销。绝大多数商业 操作系统(如Digital Unix、Solaris、Irix)都采用的这种能够完全实现POSIX1003.1c标准的线程模型。在核外实现的线程又可以分为”一对一”、”多对 一”两种模型,前者用一个核心进程(也许是轻量进程)对应一个线程,将线程调度等同于进程调度,交给核心完成,而后者则完全在核外实现多线程,调度也在用 户态完成。后者就是前面提到的单纯的用户级线程模型的实现方式,显然,这种核外的线程调度器实际上只需要完成线程运行栈的切换,调度开销非常小,但同时因 为核心信号(无论是同步的还是异步的)都是以进程为单位的,因而无法定位到线程,所以这种实现方式不能用于多处理器系统,而这个需求正变得越来越大,因 此,在现实中,纯用户级线程的实现,除算法研究目的以外,几乎已经消失了。

        Linux内核只提供了轻量进程的支持,限制了更高效的线程模型的实现,但Linux着重优化了进程的调度开销,一定程度上也弥补了这一缺陷。目前 最流行的线程机制LinuxThreads所采用的就是线程-进程”一对一”模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。 Linux-LinuxThreads的运行机制正是本文的描述重点。


    1.kthread_create kernel_thread产生的是进程还是线程,如果是线程那么进程如何产生,如果说内核线程和进程是一个东西,那么到底是进程还是线程,我在一个.C里声明个全局变量,其它的线程可以共享吗?


    2.产生内核进程用哪个函数?


    1.kthread_create kernel_thread产生的是进程还是线程,如果是线程那么进程如何产生,如果说内核线程和进程是一个东西,那么到底是进程还是线程,我在一个.C里声明个全局变量,其它的线程可以共享吗?
    答: 创建内核线程。内核线程和进程不同。
    进程,一般是应用程序运行时产生的。
    据我所知,没有内核进程这个术语。
    全局变量,其它线程可以共享。既然进程可以共享,因为一个进程可以有1个或1个以上的线程组成。不过,要注意,访问全局变量时要加锁,防止形成竞争条件。

     2.产生内核进程用哪个函数?
    答:据我所知,没有内核进程这个术语。



    没有“内核进程”。“内核线程”本身就是一种特殊的进程,它只在内核空间中运行,因此没有与之相关联的“虚拟地址空间”,也就永远不会被切换到用户空间中执行。但跟一般的进程一样,它们也是可调度的、可抢占的。这一点跟中断处理程序不一样。
    Linux一般用内核线程来执行一些特殊的操作。比如负责page cache回写的pdflush内核线程。
    另外,在Linux内核中,可调度的东西都对应一个thread_info以及一个task_struct,同一个进程中的线程,跟进程的区别仅仅是它们共享了一些资源,比如地址空间(mm_struct成员指向同一位置)。所以,如果非要觉得内核线程应该被称为“内核进程”,那也没啥不可以,只是这样说的话,就成了文字游戏了。毕竟官方的叫法就是“内核线程”。  

    对于Linux系统已经实现的“内核线程”来说,它本身就跑在内核空间中,内核中所有export出来的符号——不管是函数还是变量——它都能访问,“共享”自然是很直接的一件事。

    展开全文
  • Linux系统的三种不同类型进程

    千次阅读 2016-09-03 16:20:03
    Linux操作系统包括三种不同类型的进程: 1、交互进程:由一个shell启动的进程,既可以在前台运行,也可以在后台运行。  2、批处理进程:这种进程和终端无联系,是一个进程序列。  3、监控进程(也称为守护进程...
  • 本文声明 日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 ... Linux进程管理与调度-之-进程的创建 本章链接 链接地址 上一节 本章目录 下一节 CSDN 已是第一篇 无 Linux下0号进程的前世(ini
  • Windows系统服务与用户进程共享内存

    千次阅读 2017-05-02 23:00:37
    但我们在其他实际编程中会遇到,服务和进程通信的情况,及系统服务与用户进程共同访问共享内存,如果仍然使用这个API,你会发现,在另一个程序中Open时,是无法返回正确的HANDLE的。以下这段代码也是来自 ...
  • linux中进程用户管理

    千次阅读 2017-11-27 15:36:33
    linux中进程用户管理 每个进程都拥有真实的用户、组(uid、gid),有效的用户、组(euid、egid),保存的设置用户、组(suid、sgid),还有linux中专门用于文件存储存取的用户、组id(fsuid、fsgid对于unix系统...
  • 进程与线程

    万次阅读 多人点赞 2021-03-17 22:50:20
    进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间 动态性 进程与程序的区别在于,程序只是一...
  • 什么是进程

    万次阅读 多人点赞 2018-03-25 12:10:57
     1、用户角度: 进程是程序的一次动态执行过程  2、操作系统: 进程是操作系统分配资源的基本单位,也是最小单位 很抽象的概念,那么,到底什么是进程呢?又为什么要有进程? CPU一次只能处理一个程...
  • 什么是进程? ( 进程的详细概念 )

    万次阅读 多人点赞 2017-12-09 15:19:46
    进程管理是操作系统重点、难点问题,也是贯穿Linux学习的知识点。那么什么是进程? 为什么引入进程的概念?  从理论角度看,是对正在运行的程序过程的抽象;...  广义定义:进程是一个具有一定独立...
  • Linux守护进程--依然是进程

    千次阅读 2010-02-09 22:08:00
    在linux中,服务叫做守护进程,和windows一样,它也执行和具体用户任务无关的支撑性质的任务,可是不同于windows服务复杂的架构,linux守护进程却是一个普通的进程,除此之外它的巧妙在于它是如何成为服
  • 内核态: 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态。此时处理器处于特权级最高的(0级)内核代码中执行。...用户态: 每个进程都有自己的内核栈。当进程在执行用...
  • 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。    进程拥有这许多...
  • 转载:http://www.cnitblog.com/tarius.wu/articles/2277.html 转载:... ...内核线程只运行在内核态,不受用户
  • linux第一个用户进程init--sysvinit

    千次阅读 2014-12-28 01:20:25
    在《linux系统启动》一文中介绍了计算机从按开机键到系统启动的流程,在流程启动的最后一步就是启动系统的第一个用户进程init进程,其进程ID永为1(其实还有一个id为0的进程swap,即有名的idle进程,当cpu没有进程...
  • 转载 关于进程、线程和轻量级进程的一些笔记 ...进程是资源管理的最小单元; 线程是程序执行的最小单元。 即线程作为调度和分配的基本单位,进程作为资源分配的基本单位一个进程的组成实体可以分为两大
  • 什么是进程?什么是线程?进程与线程的区别?

    万次阅读 多人点赞 2018-07-20 10:03:57
    进程:进程是并发执行程序在执行过程中资源分配和管理的基本单位(资源分配的最小单位)。进程可以理解为一个应用程序的执行过程,应用程序一旦执行,就是一个进程。每个进程都有自己独立的地址空间,每启动一个进程...
  • 进程内核栈、用户

    千次阅读 2012-09-25 09:50:38
    from: http://www.cnblogs.com/shengge/archive/2011/08/29/2158748.html ... ...进程内核栈、用户栈 1.进程的堆栈  内核在创建进程的时候,在创建task_struct的同事,会为进程创建相应的堆栈
  • 什么是进程?什么是线程?什么是协程? 进程是什么? 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是...狭义定义:进程是正在运行的程序的实例(an i...
  • fork()函数大家应该都不陌生,一个现有进程可以调用fork函数来创建一个新进程,由fork()创建的新进程通常被称为子进程。fork()函数被调用一次,但返回两次,两次返回的区别在于,子进程的返回值为0,父进程返回值...
  • 一、定义再看正文之前我要先强调一下几点: 1. Linux中没有真正的线程,但windows中确实有线程 ... 由于Linux下没有真正的线程,只有所谓的用户级线程,线程在CPU地址空间内运行关于进程(PCB)、轻量级进程
  • (1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。 (2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的...
  • 进程和父进程的pid一定不同吗?

    千次阅读 2011-04-10 20:54:00
    进程和父进程的pid 一定不同吗? 一般来说,子父进程的pid 是不同的。 除了系统的原始的0 号进程,创建一个进程可以调用fork() 、vfork() 、clone() 函数。在/kernel/fork.c 的fork()
  • 进程中的三种用户ID

    千次阅读 2011-07-04 14:50:47
    (1)进程中三种用户ID的含义表12-2列出了进程执行时,与进程相关联的三种用户ID,这三种ID在Linux书刊中经常提及,但也是易混淆不好理解的地方。 表12-2 三种用户ID意义表 与每个进程相关联的用户ID和组ID
  • linux 查看其他用户启动的进程

    万次阅读 2012-07-17 14:40:19
    显示其他用户启动的进程(a) 查看系统中属于自己的进程(x) 启动这个进程用户和它启动的时间(u) 以下转自 http://blog.sina.com.cn/s/blog_64492fe10100qibp.html 转载 ps aux 中STAT 解释 收藏...
  • Linux C, 取得进程信息和用户信息

    千次阅读 2015-05-02 21:26:44
    同时会有不同用户,向操作系统发出各种命令。 命令通过程序执行。在执行的过程中,就会产生进程。这里我们讲程序和进程之间的关系,我们可以这样理解: 程序是一些以文件的形式存储在操作系统文件系统中,包含可...
  • 进程基础

    千次阅读 多人点赞 2019-11-03 20:07:32
    进程的基本概念 程序顺序执行的特征: 1)顺序性:处理机严格按照程序所规定的顺序执行,每一步操作必须在下一步操作开始前执行 2)封闭性:程序在封闭的环境下运行,程序独占资源,资源的状态由程序决定,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 794,100
精华内容 317,640
关键字:

不同用户的进程是通过