❶ linux 如何强制退出普通用户
先用“who”命令查询当前登录的用户
然后用“ps -u 用户名”命令查看该用户的pid
再使用“kill pid”命令,杀掉他的sshd或者是shell进程
❷ linux中 UID PID PPID 分别是什么
uid是搭肢用户id,pid是进程陆迹id,ppid是父进程id。
建议阅读linux相关书籍
比如说《linux就知悉世该这么学》。
❸ Linux里面pid是什么
就是进程号,一旦进程被创建就会有一个惟一的值来标识进程,也就是pId
❹ linux中线程pid有何作用
问题: 我的程序在其内部创建并执行了多个线程,我怎样才能在该程序创建线程后监控其中单个线程?我想要看到带有它们名称的单个线程详细情况(如,CPU/内存使用率)。
线程是现代操作系统上进行并行执行的一个流行的编程方面的抽象概念。当一个程序内有多个线程被叉分出用以执行多个流时,这些线程就会在它们之间共享 特定的资源(如,内存地址空间、打开的文件),以使叉分开销最小化,并避免大量高成本的IPC(进程间通信)通道。这些功能让线程在并发执行时成为一个高 效的机制。
在Linux中,程序中创建的线程(也称为轻量级进程,LWP)会具有和程序的PID相同的“线程组ID”。然后,各个线程会获得其自身的线程 ID(TID)。对于Linux内核调度器而言,线程不过是恰好共享特定资源的标准的进程而已。经典的命令行工具,如ps或top,都可以用来显示线程级 别的信息,只是默认情况下它们显示进程级别的信息。
这里提供了在Linux上显示某个进程的线程的几种方差备厅式。
方法一:PS
在ps命令中,“-T”选项可以开启线程查看。下面的命令列出了由进程号为<pid>的进程创建的所有线程。
1.$ ps -T -p <pid>
“SID”栏表示线程ID,而“CMD”栏则显示了线程名称。
方法二: Top
top命令可以实滚旅时显示各个线程情况。要在top输出中开启线程查看,请调用top命令的“-H”选项,该选项会列出所有Linux线程。在top运行时,你也可以通过按“H”键将线程查看模式切换为开或关。
1.$ top -H
要让top输出某个特定进程<pid>并检查该进程内运行的线程状况:
$ top -H -p <pid>
方法三: Htop
一个对用户更加友好的方式是,通过htop查看单个进程的线程,它是一个基于ncurses的交互进程查看器。该程序允许你在树状视图中监控单虚隐个独立线程。
要在htop中启用线程查看,请开启htop,然后按<F2>来进入htop的设置菜单。选择“设置”栏下面的“显示选项”,然后开启“树状视图”和“显示自定义线程名”选项。按<F10>退出设置。
现在,你就会看到下面这样单个进程的线程视图。
❺ linux中“UID、PID、PPID”分别是什么意思
具体回答如下:
UID是使用者ID,PID是程序ID,PPID是父程序ID。
UID
UID 使用者身份证明(User Identification)的缩写。UID使用者在注册会员后,系统会自动的给你一个UID的数值。意思就是给这名使用者编个号。
比如,甲在论坛注册后获得UID23 那其后乙注册应该是UID24 但是也有可能是其他,这个是整个论坛系统自动分配的。还有一个可能,比如,甲注册了论坛,UID20 但是后来他退出了,就不是会员了,但是他的UID20就空着了,其激举后的人也不能得到UID20了。
PID
PID(Process Identification)作业系统里指程序识别号,也就是程序识别符号。作业系统里每开启一个程式都会建立一个程序ID,即PID。PID(程序控制符)英文全称为Process Identifier,它也属于电工电子类技术术语。PID是各程序的代号,每个程序有唯一的PID编号。它是程序执行时系统分配的,并不代表专门的程序。在执行时PID是不会改变识别符号的,但是程序终止后PID识别符号就会被系统回明轮碧收,就可能会被继续分配给新执行的程式。
只要执行一程式,系统会自动分配一个标识。是暂时唯一:程序中止后,这个号码就会被回收,并可能被分配给另一个新程序。只要没有成功执行其他程式,这个PID会继续分配给当前要执行的程式。如果成功执行一个程式,然后再执行别的程式时,系统会自动分配另一个PID。
PPID
PPID Proct Part Identification 产品料号识别码,便于产品追踪,并含有部分资讯,一般的使用形式是产品包装上贴的一维码或二维码
计算机中代表当前程序的父程序ID;Payload protocol identifier,在S1AP通讯中标识此服务ID
美元符是表示当前使用者是普通使用者
read是系统呼叫,linux中萤幕,键盘,网络卡,终端,都被抽象成档案来考虑,你可以用read函式在这些装置上读取资料, 另外read函式不带缓冲,
cd命令:切换当前目录至其它目录。
cd / ,即进入根目录。
1、Linux是一套免费使用和自由传播的类Unix作业系统,是一个基于POSIX和UNIX的多使用者、多工、支援多执行绪和多CPU的作业系统。它能执行主要的UNIX工具软体、应用程式和网路协议。它支援32位和64位硬体。Linux继承了Unix以网路为核心的设计思想,是一个性能稳定的多使用者网路作业系统。
Linux作业系统诞生于1991 年10 月5 日(这是第一次正式向外公布时间)。Linux存在着许多不同的Linux版本,但它们都使用了Linux核心。Linux可安装在各种计算机硬体装置中,比如手机、平板电脑、路由器、视讯游戏控制台、台式计算机、大型机和超级计算机。
严格来讲,Linux这个词本身只表示Linux核心,但实际上人们已经习惯了用Linux来形容整个基于Linux核心,并且使用GNU工程各种工具和资料库的作业系统。
2、主要特性
完全相容POSIX1.0标准
这使得可以在Linux下通过相应的模拟器执行常见的DOS、Windows的程式。这为使用者从Windows转到Linux奠定了基础。许多使用者在考虑使用Linux时,就想到以前在Windows下常见的程式是否能正常执行,这一点就消除了他们的疑虑。
多使用者、多工
Linux支援多使用者,各个使用者对于自己的档案装置有自己特殊的权利,保证了各使用者之间互不影响。桐雀多工则是现在电脑最主要的一个特点,Linux可以使多个程式同时并独立地执行。
良好的接口
Linux同时具有字符接口和图形接口。在字符接口使用者可以通过键盘输入相应的指令来进行操作。它同时也提供了类似Windows图形接口的X-Window系统,使用者可以使用鼠标对其进行操作。在X-Window环境中就和在Windows中相似,可以说是一个Linux版的Windows。
支援多种平台
Linux可以执行在多种硬体平台上,如具有x86、680x0、SPARC、Alpha等处理器的平台。此外Linux还是一种嵌入式作业系统,可以执行在掌上电脑、机顶盒或游戏机上。2001年1月份释出的Linux 2.4版核心已经能够完全支援Intel64位晶片架构。同时Linux也支援多处理器技术。多个处理器同时工作,使系统性能大大提高。
TIN(triangular irregular neork):不规则三角网。指由不规则空间取样点和断线要素得到的一个对表面的近似表示, 包括点和与其相邻的三角形之间的拓扑关系。
DEM(digital elevation model):数字高程模型。以高程表达地面起伏形态的数字集合。
这都是中国移动的WLAN,随便用哪一个都可以
AIA annual investment allowance 年度补贴FYA first year allowance 第一年津贴WDA writing down allowance 写下来的津贴TWDV tax writing down value 写下了价值税Disposal 处置Balancing charge 当某项资产提了过多的capital allowance时,就会产生balancing charge,通常是资产处置的时候TWDV大于资产处置获得的收益,这是两者的差额要负的计入到capital allowance中去,减少capital allowance的值Balancing allowance 与balancing charge相反,是capital allowance提少了Special rate pool某些放在main pool,某些放在special rate pool里,它们获得资本免税额的程度不同,前者是20%,后者是10%De-pooled 把某项资产从pool中移除Separate pool 单独的一个pool,可能是有私人用途的汽车或者是short life asset,每一项资产一个单独的pool
ATP是人体内直接能源物质。化学名称三磷酸腺苷,结构式可以简写为A-P~P~P。远离A的那个P很容易水解,形成游离的Pi。同时就释放大量能量以供能,ATP就转化为ADP(二磷酸腺苷)。在有关酶的催化下,ADP可以重新与Pi结合,形成ATP。
array
配置(兵力);整(队)[H] 2. 打扮;装饰[H]
n. 1. (军队等的)列阵 2. (排列整齐的)一批;一系列;大量[(+of)] 3. 衣服;盛装 ...
[网路释义]
array 1.阵列;列阵;一批 2.建立一个新的阵列。 Array 1.阵列 2.拼版或陈列。 3.排列. 4.阵列
table 桌子
“CD”,就是指通过服装和化妆把自己打扮成为异性,所谓“变装
“TS”是指想通过外科手术变性或者已经变性的人的英文缩写。
一、CD指喜欢变装者,只喜欢变装,无改变自身性别欲望者,其性取向还是异性,跟同性恋有本质的区别。TS指认对自己的性别强烈反感,有强烈改变自己性别欲望着,
二、TS CD都喜欢着女装,TS女装一般都是平时很普通的女装, CD较性感些。
三、TS:(TransSexual)易性恋者指对本身性别不满意,而希望通过手术方式改变性别者。
CD:(Cross-Dress, Cross-Dressing, Cross Dress)女扮男装或男扮女装。
这个词是比较通俗的日常生活用语,指穿异性的服装,女扮男装或男扮女装,而不像TV较有疾病的批判意味。
secret
[英]['si:krət][美]['si:krət]
n.秘密,机密; 秘诀; 奥秘;
adj.秘密的,机密的; 神秘的; 隐秘的;
第二个单词你是不是要找recipe
recipe
[英]['resəpɪ][美][ˈrɛsəˌpi]
n.食谱; 处方; 秘诀;
复数:recipes
❻ linux下 为什么当用户在后台执行进程时PID很有用
因为pid可以看出现在正在运行什么芹轮培类型的程序啊,使用ps -aux可以全部看出,是什么程序在运行,他的父进程是什么,子嫌唯进程又有哪些!桐缓
❼ linux下的PID,PIDD是什么他们之间的关系以及应用是什么
在 Linux 底下执行一个指令时,系统会给予这个动作一个 ID, 我们称为 PID,而根据启用这个指令的使用者与相关的指令功能,而给予这个特定 PID 一组权限, 该指令可以进行的行为则与这个 PID 的权限有关。
linux进程简介
Linux是一个多任务的操作系统,也就是说,在同一个时间内,可以有多个进程同时执行。如果读者对计算机硬件体系有一定了解的话,会知道我们大家常用的单CPU计算机实际上在一个时间片断内只能执行一条指令,那么Linux是如何实现多进程同时执行的呢?原来Linux使用了一种称为"进程调度(process scheling)"的手段,首先,为每个进程指派一定的运行时间,这个时间通常很短,短到以毫秒为单位,然后依照某种规则,从众多进程中挑选一个投入运行,其他的进程暂时等待,当正在运行的那个进程时间耗尽,或执行完毕退出,或因某种原因暂停,Linux就会重新进行调度,挑选下一个进程投入运行。因为每个进程占用的时间片都很短,在我们使用者的角度来看,就好像多个进程同时运行一样了。
在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(Process Control Block,简称PCB)。PCB中包含了很多重要的信息,供系统调度和进程本身执行使用,其中最重要的莫过于进程ID(process ID)了,进程ID也被称作进程标识符,是一个非负的整数,在Linux操作系统中唯一地标志一个进程,在我们最常使用的I386架构(即PC使用的架构)上,一个非负的整数的变化范围是0-32767,这也是我们所有可能取到的进程ID。其实从进程ID的名字就可以看出,它就是进程的身份证号码,每个人的身份证号码都不会相同,每个进程的进程ID也不会相同。
一个或多个进程可以合起来构成一个进程组(process group),一个或多个进程组可以合起来构成一个会话(session)。这样我们就有了对进程进行批量操作的能力,比如通过向某个进程组发送信号来实现向该组中的每个进程发送信号。
最后,让我们通过ps命令亲眼看一看自己的系统中目前有多少进程在运行:
$ps -aux(以下是在我的计算机上的运行结果,你的结果很可能与这不同。)
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.4 1412 520 ? S May15 0:04 init [3]
root 2 0.0 0.0 0 0 ? SW May15 0:00 [keventd]
root 3 0.0 0.0 0 0 ? SW May15 0:00 [kapm-idled]
root 4 0.0 0.0 0 0 ? SWN May15 0:00 [ksoftirqd_CPU0]
root 5 0.0 0.0 0 0 ? SW May15 0:00 [kswapd]
root 6 0.0 0.0 0 0 ? SW May15 0:00 [kreclaimd]
root 7 0.0 0.0 0 0 ? SW May15 0:00 [bdflush]
root 8 0.0 0.0 0 0 ? SW May15 0:00 [kupdated]
root 9 0.0 0.0 0 0 ? SW< May15 0:00 [mdrecoveryd]
root 13 0.0 0.0 0 0 ? SW May15 0:00 [kjournald]
root 132 0.0 0.0 0 0 ? SW May15 0:00 [kjournald]
root 673 0.0 0.4 1472 592 ? S May15 0:00 syslogd -m 0
root 678 0.0 0.8 2084 1116 ? S May15 0:00 klogd -2
rpc 698 0.0 0.4 1552 588 ? S May15 0:00 portmap
rpcuser 726 0.0 0.6 1596 764 ? S May15 0:00 rpc.statd
root 839 0.0 0.4 1396 524 ? S May15 0:00 /usr/sbin/apmd -p
root 908 0.0 0.7 2264 1000 ? S May15 0:00 xinetd -stayalive
root 948 0.0 1.5 5296 1984 ? S May15 0:00 sendmail: accepti
root 967 0.0 0.3 1440 484 ? S May15 0:00 gpm -t ps/2 -m /d
wnn 987 0.0 2.7 4732 3440 ? S May15 0:00 /usr/bin/cserver
root 1005 0.0 0.5 1584 660 ? S May15 0:00 crond
wnn 1025 0.0 1.9 3720 2488 ? S May15 0:00 /usr/bin/tserver
xfs 1079 0.0 2.5 4592 3216 ? S May15 0:00 xfs -droppriv -da
daemon 1115 0.0 0.4 1444 568 ? S May15 0:00 /usr/sbin/atd
root 1130 0.0 0.3 1384 448 tty1 S May15 0:00 /sbin/mingetty tt
root 1131 0.0 0.3 1384 448 tty2 S May15 0:00 /sbin/mingetty tt
root 1132 0.0 0.3 1384 448 tty3 S May15 0:00 /sbin/mingetty tt
root 1133 0.0 0.3 1384 448 tty4 S May15 0:00 /sbin/mingetty tt
root 1134 0.0 0.3 1384 448 tty5 S May15 0:00 /sbin/mingetty tt
root 1135 0.0 0.3 1384 448 tty6 S May15 0:00 /sbin/mingetty tt
root 8769 0.0 0.6 1744 812 ? S 00:08 0:00 in.telnetd: 192.1
root 8770 0.0 0.9 2336 1184 pts/0 S 00:08 0:00 login -- lei
lei 8771 0.1 0.9 2432 1264 pts/0 S 00:08 0:00 -bash
lei 8809 0.0 0.6 2764 808 pts/0 R 00:09 0:00 ps -aux
以上除标题外,每一行都代表一个进程。在各列中,PID一列代表了各进程的进程ID,COMMAND一列代表了进程的名称或在Shell中调用的命令行,对其他列的具体含义,我就不再作解释,有兴趣的读者可以去参考相关书籍。
getpid
在2.4.4版内核中,getpid是第20号系统调用,其在Linux函数库中的原型是:
#include<sys/types.h> /* 提供类型pid_t的定义 */
#include<unistd.h> /* 提供函数的定义 */
pid_t getpid(void);
getpid的作用很简单,就是返回当前进程的进程ID,请大家看以下的例子:
/* getpid_test.c */
#include<unistd.h>
main()
{
printf("The current process ID is %d
",getpid());
}
细心的读者可能注意到了,这个程序的定义里并没有包含头文件sys/types.h,这是因为我们在程序中没有用到pid_t类型,pid_t类型即为进程ID的类型。事实上,在i386架构上(就是我们一般PC计算机的架构),pid_t类型是和int类型完全兼容的,我们可以用处理整形数的方法去处理pid_t类型的数据,比如,用"%d"把它打印出来。
编译并运行程序getpid_test.c:
$gcc getpid_test.c -o getpid_test
$./getpid_test
The current process ID is 1980
(你自己的运行结果很可能与这个数字不一样,这是很正常的。)
再运行一遍:
$./getpid_test
The current process ID is 1981
正如我们所见,尽管是同一个应用程序,每一次运行的时候,所分配的进程标识符都不相同。
fork
在2.4.4版内核中,fork是第2号系统调用,其在Linux函数库中的原型是:
#include<sys/types.h> /* 提供类型pid_t的定义 */
#include<unistd.h> /* 提供函数的定义 */
pid_t fork(void);
只看fork的名字,可能难得有几个人可以猜到它是做什么用的。fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。据说fork的名字就是来源于这个与叉子的形状颇有几分相似的工作流程。
在Linux中,创造新进程的方法只有一个,就是我们正在介绍的fork。其他一些库函数,如system(),看起来似乎它们也能创建新的进程,如果能看一下它们的源码就会明白,它们实际上也在内部调用了fork。包括我们在命令行下运行应用程序,新的进程也是由shell调用fork制造出来的。fork有一些很有意思的特征,下面就让我们通过一个小程序来对它有更多的了解。
/* fork_test.c */
#include<sys/types.h>
#inlcude<unistd.h>
main()
{
pid_t pid;
/*此时仅有一个进程*/
pid=fork();
/*此时已经有两个进程在同时运行*/
if(pid<0)
printf("error in fork!");
else if(pid==0)
printf("I am the child process, my process ID is %d
",getpid());
else
printf("I am the parent process, my process ID is %d
",getpid());
}
编译并运行:
$gcc fork_test.c -o fork_test
$./fork_test
I am the parent process, my process ID is 1991
I am the child process, my process ID is 1992
看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if(pid==0)......。
两个进程中,原先就存在的那个被称作"父进程",新出现的那个被称作"子进程"。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
在父进程中,fork返回新创建子进程的进程ID;
在子进程中,fork返回0;
如果出现错误,fork返回一个负值;
fork出错可能有两种原因:
(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。(2)系统内存不足,这时errno的值被设置为ENOMEM。(关于errno的意义,请参考本系列的第一篇文章。)
fork系统调用出错的可能性很小,而且如果出错,一般都为第一种错误。如果出现第二种错误,说明系统已经没有可分配的内存,正处于崩溃的边缘,这种情况对Linux来说是很罕见的。
说到这里,聪明的读者可能已经完全看懂剩下的代码了,如果pid小于0,说明出现了错误;pid==0,就说明fork返回了0,也就说明当前进程是子进程,就去执行printf("I am the child!"),否则(else),当前进程就是父进程,执行printf("I am the parent!")。完美主义者会觉得这很冗余,因为两个进程里都各有一条它们永远执行不到的语句。不必过于为此耿耿于怀,毕竟很多年以前,UNIX的鼻祖们在当时内存小得无法想象的计算机上就是这样写程序的,以我们如今的"海量"内存,完全可以把这几个字节的顾虑抛到九霄云外。
说到这里,可能有些读者还有疑问:如果fork后子进程和父进程几乎完全一样,而系统中产生新进程唯一的方法就是fork,那岂不是系统中所有的进程都要一模一样吗?那我们要执行新的应用程序时候怎么办呢?从对Linux系统的经验中,我们知道这种问题并不存在。至于采用了什么方法,我们把这个问题留到后面具体讨论。
exit
在2.4.4版内核中,exit是第1号调用,其在Linux函数库中的原型是:
#include<stdlib.h>
void exit(int status);
不像fork那么难理解,从exit的名字就能看出,这个系统调用是用来终止一个进程的。无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。请看下面的程序:
/* exit_test1.c */
#include<stdlib.h>
main()
{
printf("this process will exit!
");
exit(0);
printf("never be displayed!
");
}
编译后运行:
$gcc exit_test1.c -o exit_test1
$./exit_test1
this process will exit!
我们可以看到,程序并没有打印后面的"never be displayed! ",因为在此之前,在执行到exit(0)时,进程就已经终止了。
exit系统调用带有一个整数类型的参数status,我们可以利用这个参数传递进程结束时的状态,比如说,该进程是正常结束的,还是出现某种意外而结束的,一般来说,0表示没有意外的正常结束;其他的数值表示出现了错误,进程非正常结束。我们在实际编程时,可以用wait系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理。关于wait的详细情况,我们将在以后的篇幅中进行介绍。
exit和_exit
作为系统调用而言,_exit和exit是一对孪生兄弟,它们究竟相似到什么程度,我们可以从Linux的源码中找到答案:
#define __NR__exit __NR_exit /* 摘自文件include/asm-i386/unistd.h第334行 */
"__NR_"是在Linux的源码中为每个系统调用加上的前缀,请注意第一个exit前有2条下划线,第二个exit前只有1条下划线。
这时随便一个懂得C语言并且头脑清醒的人都会说,_exit和exit没有任何区别,但我们还要讲一下这两者之间的区别,这种区别主要体现在它们在函数库中的定义。_exit在Linux函数库中的原型是:
#include<unistd.h>
void _exit(int status);
和exit比较一下,exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中,从名字上看,stdlib.h似乎比unistd.h高级一点,那么,它们之间到底有什么区别呢?让我们先来看流程图,通过下图,我们会对这两个系统调用的执行过程产生一个较为直观的认识。
从图中可以看出,_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。
exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的"清理I/O缓冲"一项。
在Linux的标准函数库中,有一套称作"高级I/O"的函数,我们熟知的printf()、fopen()、fread()、fwrite()都在此列,它们也被称作"缓冲I/O(buffered I/O)",其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符和文件结束符EOF),再将缓冲区中的内容一次性写入文件,这样就大大增加了文件读写的速度,但也为我们编程带来了一点点麻烦。如果有一些数据,我们认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时我们用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失,反之,如果想保证数据的完整性,就一定要使用exit()函数。
请看以下例程:
/* exit2.c */
#include<stdlib.h>
main()
{
printf("output begin
");
printf("content in buffer");
exit(0);
}
编译并运行:
$gcc exit2.c -o exit2
$./exit2
output begin
content in buffer
/* _exit1.c */
#include<unistd.h>
main()
{
printf("output begin
");
printf("content in buffer");
_exit(0);
}
编译并运行:
$gcc _exit1.c -o _exit1
$./_exit1
output begin
在Linux中,标准输入和标准输出都是作为文件处理的,虽然是一类特殊的文件,但从程序员的角度来看,它们和硬盘上存储数据的普通文件并没有任何区别。与所有其他文件一样,它们在打开后也有自己的缓冲区。
请读者结合前面的叙述,思考一下为什么这两个程序会得出不同的结果。相信如果您理解了我前面所讲的内容,会很容易的得出结论。
在这篇文章中,我们对Linux的进程管理作了初步的了解,并在此基础上学习了getpid、fork、exit和_exit四个系统调用。在下一篇文章中,我们将学习与Linux进程管理相关的其他系统调用,并将作一些更深入的探讨。
前面的文章中,我们已经了解了父进程和子进程的概念,并已经掌握了系统调用exit的用法,但可能很少有人意识到,在一个进程调用了exit之后,该进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构。在Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。从这点来看,僵尸进程虽然有一个很酷的名字,但它的影响力远远抵不上那些真正的僵尸兄弟,真正的僵尸总能令人感到恐怖,而僵尸进程却除了留下一些供人凭吊的信息,对系统毫无作用。
也许读者们还对这个新概念比较好奇,那就让我们来看一眼Linux里的僵尸进程究竟长什么样子。
当一个进程已退出,但其父进程还没有调用系统调用wait(稍后介绍)对其进行收集之前的这段时间里,它会一直保持僵尸状态,利用这个特点,我们来写一个简单的小程序:
/* zombie.c */
#include
#include
main()
{
pid_t pid;
pid=fork();
if(pid<0) /* 如果出错 */
printf("error occurred!n");
else if(pid==0) /* 如果是子进程 */
exit(0);
else /* 如果是父进程 */
sleep(60); /* 休眠60秒,这段时间里,父进程什么也干不了 */
wait(NULL); /* 收集僵尸进程 */
}
sleep的作用是让进程休眠指定的秒数,在这60秒内,子进程已经退出,而父进程正忙着睡觉,不可能对它进行收集,这样,我们就能保持子进程60秒的僵尸状态。
编译这个程序:
$ cc zombie.c -o zombie
后台运行程序,以使我们能够执行下一条命令:
$ ./zombie &
[1] 1577
列一下系统内的进程:
$ ps -ax
... ...
1177 pts/0 S 0:00 -bash
1577 pts/0 S 0:00 ./zombie
1578 pts/0 Z 0:00 [zombie ]
1579 pts/0 R 0:00 ps -ax
看到中间的"Z"了吗?那就是僵尸进程的标志,它表示1578号进程现在就是一个僵尸进程。
我们已经学习了系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁。僵尸进程虽然对其他进程几乎没有什么影响,不占用CPU时间,消耗的内存也几乎可以忽略不计,但有它在那里呆着,还是让人觉得心里很不舒服。而且Linux系统中进程数目是有限制的,在一些特殊的情况下,如果存在太多的僵尸进程,也会影响到新进程的产生。那么,我们该如何来消灭这些僵尸进程呢?
先来了解一下僵尸进程的来由,我们知道,Linux和UNIX总有着剪不断理还乱的亲缘关系,僵尸进程的概念也是从UNIX上继承来的,而UNIX的先驱们设计这个东西并非是因为闲来无聊想烦烦其他的程序员。僵尸进程中保存着很多对程序员和系统管理员非常重要的信息,首先,这个进程是怎么死亡的?是正常退出呢,还是出现了错误,还是被其它进程强迫退出的?其次,这个进程占用的总系统CPU时间和总用户CPU时间分别是多少?发生页错误的数目和收到信号的数目。这些信息都被存储在僵尸进程中,试想如果没有僵尸进程,进程一退出,所有与之相关的信息都立刻归于无形,而此时程序员或系统管理员需要用到,就只好干瞪眼了。
那么,我们如何收集这些信息,并终结这些僵尸进程呢?就要靠我们下面要讲到的waitpid调用和wait调用。这两者的作用都是收集僵尸进程留下的信息,同时使这个进程彻底消失。下面就对这两个调用分别作详细介绍。