? ? 和文件一样,进程是Unix系统最基本的抽象之一。
一、进程ID
????每一个进程都有一个唯一的标示,进程ID。虽然进程ID是唯一的,但进程终止后,id会被其他进程重用。许多UNIX都提供了延迟重用的功能,以防止新进程被误认为是旧进程。
?
????有一些特殊的进程:
id为0的进程--idle进程或者叫做swapper,通常是一个调度进程。
id为1的进程--内核booting之后执行的第一个进程。init进程一般执行的是init程序。
?
????Linux通常尝试执行以下init程序:
1、/sbin/init: 偏向、最有可能是init程序的地方。
2、/etc/init: 另一个很有可能是init程序的地方。
3、/bin/init: 有可能是init进程的地方。
4、/bin/sh:如果内核找不到init进程,就执行该bourne shell。
????init进程是一个用户级进程,但是需要执行者有超级用户权限。
?
二、获得进程ID和父进程的ID
?
? ? #include <sys/types.h> ?
? ? #include <unistd.h> ?
? ? ??
? ? pid_t getpid(void); ?
? ? pit_t getppid(void); ?
?
?
????pid_t是个抽象类型,在linux中pid_t一般是一个int类型,在<sys/types.h>定义。但把pid_t当做int类型,不具有可移植性。
?
? ? printf("My pid=%d/n",getpid()); ?
? ? printf("Parent's pid=%d/n",getppid()); ?
?
????我们可以把pid_t比较安全的当做int类型,虽然这违反了抽象类型的意图和可移植性。
?
三、创建一个进程fork
????一个已经存在的进程可以通过fork创建其他进程:
?
? ? #include <unistd.h> ?
? ? pid_t fork(void); ?
?
?
新创建的进程被称为子进程,这个函数被调用一次但是被返回两次。在子进程返回0,父进程返回子进程的t_pid。
之所以在父进程返回子进程的id,是由于父进程可以有多个子进程,并且没有提供获得所有子进程的方法。在子进程
中返回0,是因为子进程只有一个父进程,并且可以通过getppid获得。
fork被调用之后,父进程和子进程都开始执行fork之后的程序语句。子进程是父进程的一个拷贝,拷贝了父进程的数据
空间,堆,栈,它们共享text段。
当前fork的实现并不是拷贝父进程的数据、堆、栈,而是使用了copy-on-write技术,这是因为fork之后通常会调用exec。
如果它们修改了这些区域,那么内核就会把相应的那部分内存进行拷贝。
子进程和父进程有以下不同:
1)进程id不同
2) fork的返回值不同
2)子进程的父进程id设置为父进程的id,它们的父进程不同
3)子进程的资源统计归为0
4)任何pending的signals被清空,不会被子进程继承
5)任何获得的文件锁都不会被子进程继承。
相同的:
1)打开文件
2)real user ID,real group ID,effective user ID,effective group ID
3)进程的group ID
4)Session ID
5)控制终端
6)set-user-ID和set-group-ID
7)当前工作目录
8)Root目录
9)文件mode创建的掩码
10)信号掩码和dipositions
11)打开文件的close-on-exec flag
12)环境变量
13)附加进去的共享内存段
14)内存映像
15)资源限制
如果失败返回-1。
例子:
?
? ? pid_t pid; ?
? ? ??
? ? pid = fork(); ?
? ? if(pid > 0){ ?
? ? ? ? printf("I am the parent of pid=%d/n",pid); ?
? ? }else if(!pid){ ?
? ? ? ? printf("I am the baby!/n"); ?
? ? }else if(pid == -1){ ?
? ? ? ? perror("fork"); ?
? ? } ?
?
?
fork经常和exec在一起使用:
Cpp代码 复制代码
?
? ? pid_t pid; ??
? ? ??
? ? pid = fork(); ??
? ? if(pid == -1) ??
? ? ? ? perror("fo