Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97139
  • 博文数量: 45
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 395
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-15 10:29
文章分类

全部博文(45)

文章存档

2011年(15)

2010年(30)

我的朋友

分类:

2011-03-01 12:25:07

 

三、getpid

2.4.4版内核中,getpid是第20号系统调用,其在Linux函数库中的原型是:

         #include /* 提供类型pid_t的定义 */

         #include /* 提供函数的定义 */

pid_t getpid(void);

getpid的作用很简单,就是返回当前进程的进程ID,请大家看以下的例子:

/* getpid_test.c *

/#include

main()

{      

printf("The current process ID is %d\n",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  /* 提供类型pid_t的定义 */

         #include /* 提供函数的定义 */

             pid_t fork(void);

只看fork的名字,可能难得有几个人可以猜到它是做什么用的。fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。据说fork的名字就是来源于这个与叉子的形状颇有几分相似的工作流程。

Linux 中,创造新进程的方法只有一个,就是我们正在介绍的fork。其他一些库函数,如system(),看起来似乎它们也能创建新的进程,如果能看一下它们的源码就会明白,它们实际上也在内部调用了fork。包括我们在命令行下运行应用程序,新的进程也是由shell调用fork制造出来的。fork有一些很有意思的特征,下面就让我们通过一个小程序来对它有更多的了解。

/* fork_test.c */

#include

#inlcude

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\n",getpid());

         else           

printf("I am the parent process, my process ID is %d\n",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系统的经验中,我们知道这种问题并不存在。至于采用了什么方法,我们把这个问题留到后面具体讨论。

阅读(642) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~