1、进程标志
进程ID标识符是唯一、可复用的。大多数Unix系统实现延迟复用算法,使得赋予新建进程的ID不同于最近终止所使用的ID
ID为0的进程通常是调度进程,也常被称为交换进程。它是内核的一部分,是系统进程。
ID为1的进程通常是init进程,在自举过程结束时由内核调用。该进程负责在内核自举后启动一个Unix系统,它决不会终止,是一个普通的用户进程,但以超级用户特权运行。
ID为2的进程是页守护进程,负责支持虚拟存储器系统的分页操作
除了进程ID ,每个进程还有一些其他标识符。下列函数返回这些标识符
#include <unistd.h> pid_t getpid(void); //返回调用进程的进程ID pid_t getppid(void); //返回调用进程的父进程ID uid_t getuid(void); //返回调用进程的实际用户ID uid_t geteuid(void) //返回调用进程的有效用户ID gid_t getgid(void); //返回调用进程的实际组ID gid_t getegid(void); //返回调用进程的有效组ID
本文地址:http://wuyudong.com/2016/10/24/2894.html,转载请注明出处。
2、函数fork
一个现有的进程可以调用fork函数创建一个新进程
#include <unistd.h>
pid_t fork(void);
//返回值:子进程返回0;父进程返回进程ID;若出错,返回-1
fork函数被调用一次,返回两次。子进程中返回值是0,父进程中返回值是子进程的pid
子进程是父进程的副本,子进程获得父进程的数据空间、堆和栈的副本。注意,在是子进程拥有的副本。父子进程并不共享这些存储空间部分。父子进程共享正文段。
由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、堆和栈的完全副本。作为替代,使用了写时复制技术。
#include "apue.h" int globvar = 6; char buf[] = "a write to stdout\n"; int main(void) { int var; /* 在栈上的自动变量 */ pid_t pid; var = 88; if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1) err_sys("write error"); printf("before fork\n"); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* 子进程 */ globvar++; var++; } else { sleep(2); /* 父进程 */ } printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); exit(0); }
运行程序
wu@ubuntu:~/apue.3e/proc$ ./fork1
a write to stdout
before fork
pid = 28356, glob = 7, var = 89
pid = 28355, glob = 6, var = 88
可以看到,子进程的glob和var的值改变了,而父进程的没有改变
一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的调度算法。如果要求父进程和子进程之间相互同步,则要求某种形式的进程间通信。
父进程和子进程每个相同的打开描述符共享一个文件表项。
重点是,父进程和子进程共享同一个文件偏移量。
在fork之后处理文件描述符有以下两种常见的情况。
1. 父进程等待子进程完成。在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它层进行过读、写操作的任一共享描述符的文件偏移量已做了相应更新。
2. 父进程和子进程各自执行不同的程序段。在这种情况下,在fork之后,父进程和子进程各自关闭它们不需使用的文件描述符,这样就不会干扰对方使用的文件描述符。这种方法是网络服务进程经常使用的。
除了打开文件之外,父进程的很多其他属性也由子进程继承,包括:
实际用户ID、实际组ID、有效用户ID、有效组ID
附属组ID
进程组ID
会话ID
控制终端
设置用户ID标志和设置组ID标志
当前工作目录
根目录
文件模式创建屏蔽字
信号屏蔽和安排
对任一打开文件描述符的执行时关闭标志
环境
连接的共享存储段
存储映像
资源限制
父进程和子进程之间的区别具体如下。
fork的返回值不同
进程ID不同
这两个进程的父进程ID不同:子进程的父进程ID是创建它的进程的ID,而父进程的父进程ID则不变。
子进程的tms_utime、tms_stime、tms_cutime和tms_ustime的值设置为0
子进程不继承父进程设置的文件锁
子进程的未处理闹钟被清除
子进程的未处理信号集设置为空集
使fork失败的两个主要的原因是:(a)系统中已经有了太多的进程,(b)该实际用户ID的进程总数超过了系统限制。
fork有以下两种用法
1. 一个父进程希望复制自己,使父进程和子进程同时执行不同的代码段。这在网络服务器进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求。
2. 一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec
Comments