现在的位置: 首页 > 综合 > 正文

进程相关的系统调用1

2013年02月19日 ⁄ 综合 ⁄ 共 2769字 ⁄ 字号 评论关闭

 

说明:只供学习交流,转载请注明出处

 

一,获取ID

getpidgetppid函数

 

头文件

#include <sys/types.h>

#include <unistd.h>

函数原型

pid_t getpid(void);

pid_t getppid(void);

返回值

getpid返回当前进程id号。

getppid返回父进程id号。

实例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[])
{

        printf("PID = %d\n", getpid());
        printf("PPID = %d\n", getppid());

        return (0);
}

运行结果:
[root@localhost test]# ./getpid 
PID = 24858
PPID = 24361
[root@localhost test]#


 

二,创建子进程

fork函数

 

头文件

#include <unistd.h>

函数原型

pid_t fork(void);

返回值

子进程中返回0,父进程中返回子进程的ID,出错返回-1

说明:fork的奇妙之处在于它被调用一次,却返回两次,它可能有三种不同的返回值:

1):在父进程中,fork返回新创建的子进程的PID

2):在子进程中,fork返回0

3):如果出现错误,fork返回一个负值

 

注意:用fork创建的子进程,子进程和父进程共享代码段,但不共享数据段和堆栈段。子进程会拷贝一份父进程的数据段和堆栈段,作为自己独立的数据段和堆栈段。

 

请看下面的例子并分析会输出什么:

#include <unistd.h>
#include <stdio.h>
int main(void)
{
pid_t pid;
int count=0;
pid = fork();
count++;
printf( “count = %d\n", count );
return 0;
}
答案是:
[root@localhost test]# ./fork 
count = 1
count = 1


 

分析:

子进程的数据空间、堆栈空间都会从父进程得到一个拷贝,而不是共享。在子进程中对count进行加1的操作,并没有

影响到父进程中的count值,父进程中的count值仍然为0

 

实例:

 

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
        pid_t pid;

        pid = fork();

        if ( pid < 0 )
        {
                printf("Creat child process error!!\n");
                exit(EXIT_FAILURE);
        }
        else if(pid == 0)
        {
                printf("I am child process, ID is %d\n", getpid());
        }
        else
        {
                printf("I am parent process, ID is %d\n", getppid());

        return (0);
}

运行结果:

[root@localhost test]# ./fork1
I am child process, ID is 25397
I am parent process, ID is 24361


 

说明:虽然说,用fork创建子进程,子进程和父进程的执行顺序是不确定的,但我运行了很多次,总是子进程先运行,不知道是巧合,还是什么的,待研究。

 

 

vfork函数

 

头文件

#include <unistd.h>

函数原型

pid_t vfork(void);

返回值

子进程中返回0,父进程中返回子进程ID,出错返回-1

 

forkvfork的区别:

传统的fork函数在创建新的子进程的时候会复制所有父进程所拥有的资源(例如,进程环境,内存,堆栈,数据段等)。这一复制进程方法有一定的问题,因为使用fork函数创建新的进程的目的往往不是为了创建一个和父进程完全一样的进程,很多时候是为了调用exec来执行另一个可执行程序。因此复制所有父进程是多余的操作。

vfork函数是用来解决这个问题的。当使用vfork系统调用来创建子进程的时候,不会复制父进程的相关资源,父子进程将共享地址空间。子进程对虚拟内存空间的任何修改实际上是修改父进程虚拟内存空间的内容。

在使用vfork函数创建子进程后,父进程会被阻塞,直到子进程调用了exec或者_exit函数退出。子进程不能使用return返回或调用exit函数,但是可以调用_exit函数。通过共享父进程的地址空间,vfork避免了fork带来的资源复制的消耗。

 

还是上面的那个例子:

#include <unistd.h>
#include <stdio.h>
int main(void)
{
pid_t pid;
int count=0;
pid = fork();
count++;
printf( “count = %d\n", count );
_exit(0);
}

这次输出的结果是:
[root@localhost test]# ./fork
count = 1
count = 2


 

结果就不要解释了吧,呵呵。

 

补充:

vfork的出现促进了fork机制的改变。目前,Linux系统实现fork系统调用采用了“写操作时复制(copy-on-writeCOW)”的方法。COW是一种延迟资源复制的方法,子进程在创建的时候并不复制父进程的相关资源,父子进程通过访问相同的物理内存来伪装已经实现了对资源的复制。这种共享是只读方式,这一点与vfork是不同的。当子进程对内存数据存在写入操作的时候,才会进行资源的复制。

COW机制使得vfork几乎没有存在的必要了,但是出于兼容性的考虑,系统还是提供了该接口。由于使用vfork时,子进程对内存的修改会影响父进程,这一点在编程时必须特别注意。

 

vfork实例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
        pid_t pid;

        pid = vfork();

        if ( pid < 0 )
        {
                printf("Cannot create new process!\n");
                exit(EXIT_FAILURE);
        }
        else if(pid == 0)
        {
                sleep(3);
                printf("I am child process, PID = %d\n", getpid());
                _exit(0);
        }
        Else
{
                printf("I am parent process, PId = %d\n", getpid());
        }

        return (0);

}

运行结果:
[root@localhost test]# ./vfork 
I am child process, PID = 26839
I am parent process, PId = 26838

 

 

 

 

 

 

 

 

 

 

 

抱歉!评论已关闭.