各大设计网站,网络营销简介,南昌高端模板建站,网站平台建立一、进程标识#xff08;pid#xff09; 每个进程都有一个非负整数形式的唯一编号#xff0c;即 PID。PID 在任何时刻都是唯一的#xff0c;但是可以重用#xff0c;当进程终止并被回收以后#xff0c;其 PID 就可以为其它进程所用。进程的 PID 由系统内核根据延迟重用算…一、进程标识pid 每个进程都有一个非负整数形式的唯一编号即 PID。PID 在任何时刻都是唯一的但是可以重用当进程终止并被回收以后其 PID 就可以为其它进程所用。进程的 PID 由系统内核根据延迟重用算法生成以确保新进程的 PID 不同于最近终止进程的 PID。
1、特殊的进程标识 0 号进程调度进程通常是调度进程常常被称为交换进程swapper。该进程是内核的一部分所有进程的根进程它并不执行任何磁盘上的程序因此也被称为系统进程。 1 号进程init进程通常是 init 进程在自举过程结束时由内核调用。 2号进程页守护进程负责虚拟内存系统的分页操作。 2、获取进程标识
#include sys/types.h
#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
注意这些函数都没有出错返回
二、进程创建fork和父子进程
#include unistd.h
pid_t fork(void);
1、函数功能 fork()主要用于以复制正在调用进程的方式去创建一个新的进程新进程叫做子进程原来的进程叫做父进程。
2、与fork()相关的一些问题 1由 fork()创建的新进程被称为子进程。fork()函数调用一次但返回两次。两次返回的区别是子进程的返回值是 0而父进程的返回值则是新建子进程的进程 ID。通过fork()的返回值来区别父子进程如果出错返回-1。 2调用fork()前的代码只有父进程执行fork()成功返回后的代码父子进程都会执行。 3将新建子进程 ID 返回给父进程的理由因为一个进程的子进程可以有多个并且没有一个函数使一个进程可以获得其所有子进程的 ID。 4fork 使子进程得到返回值 0 的理由一个进程只会有一个父进程所以子进程总是可以调用 getppid 以获得其父进程的进程 ID进程 ID 0 总是由内核交换进程使用所以一个子进程的进程 ID 不可能为 0。 5调用fork()出错的原因系统中已经存在太多的进程调用函数fork()的用户进程太多。 3、fork()写时复制 子进程是父进程的不完全副本。子进程的数据区、bbs区、堆栈区包括 I/O 流缓冲区甚至参数和环境区都从父进程拷贝唯有代码区与父进程共享。 因为代码区是可执行指令 、字面值常量 、具有常属性且被 初始化的全局、静态全局 和 静态局部变量。 传统的fork()系统调用直接把所有的资源复制给新创建的进程这种实现过于简单并且效率低下。Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间而是让父子进程共享同一个地址空间。只在需要写入的时候才会复制地址空间从而使各个进程拥有各自的地址空间。也就是说资源的复制是在需要写入的时候才会进行在此之前只有以只读方式共享。只有进程空间的各段的内容要发生变化时才会将父进程的内容复制一份给子进程。 4、文件共享 在重定向父进程的标准输出时子进程的标准输出也被重定向了。fork的一个特性是进程的所有打开文件描述符都被复制到子进程中。在 fork 之后处理文件描述符有以下两种常用的操作模式 1. 父进程等待子进程完成在这种情况下父进程无需对其描述符做任何处理。当子进程终止后它曾进行过读、写操作的任一共享描述符的文件偏移量已做了相应更新。 2. 父进程和子进程各自执行不同的程序段在这种情况下在 fork 之后父进程和子进程各自关闭它们不需使用的文件描述符这样就不会干扰对方使用的文件描述符。这种方法是网络服务进程经常使用的。 5、父进程和子进程之间的区别 fork 的返回值不同子进程返回 0 而父进程返回新建子进程 ID。进程 ID 不同。这两个进程的父进程 ID 不同子进程的父进程 ID 是创建它的进程的 ID而父进程的父进程 ID 则不变。子进程的tms_utime , tms_stime , tms_cutime以及tms_ustime设置为0。子进程不继承父进程设置的文件锁。子进程的未处理闹钟被清除。子进程的未处理信号集设置为空集。 #include unistd.h
#include stdio.h
#include stdlib.hint main()
{pid_t pid;// fork函数被调用一次但返回两次在父进程中返回子进程的pid子进程返回0pid fork(); // 产生父子进程if (pid 0) // 父进程执行代码段{while(1){printf(I am parent\n);printf(my pid %d,getpid());printf(my parent pid %d,getpid());sleep(1);}}else if (pid 0) // 子进程执行代码段{while(1){printf(I am child\n);printf(my pid %d,getpid());printf(my parent pid %d,getppid());sleep(3);}}else{perror(fork); //打印出错信息exit(1);}return 0;
}
三、fork()vfork()和clone()的区别
1、进程四要素 有一段程序供其执行不一定是一个进程所专有的就像一场戏必须有自己的剧本。有自己的专用系统堆栈空间私有财产。有进程控制块task_struct“有身份证PID”。有独立的存储空间。 缺少第四条的称为线程如果完全没有用户空间称为内核线程共享用户空间的称为用户线程。 2、fork() fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间而是让父子进程共享同一个地址空间。只在需要写入的时候才会复制地址空间从而使各个进程拥有各自的地址空间。 3、vfork() vfork也是创建一个子进程但是子进程共享父进程的空间。在vfork创建子进程之后父进程阻塞直到子进程执行了exec()或者exit()。 vfork创建出来的不是真正意义上的进程而是一个线程因为它缺少第四个要素独立的内存资源。 另外由vfork创建的子进程要先于父进程执行子进程执行时父进程处于挂起状态子进程执行完唤醒父进程。除非子进程exit或者execve才会唤起父进程。 4、clone() clone是Linux为创建线程设计的虽然也可以用clone创建进程。所以可以说clone是fork的升级版本不仅可以创建进程或者线程还可以指定创建新的命名空间namespace、有选择的继承父进程的内存、甚至可以将创建出来的进程变成父进程的兄弟进程等等。 int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); clone和fork最大不同在于clone不再复制父进程的栈空间而是自己创建一个新的。 void *child_stack也就是第二个参数需要分配栈指针的空间大小所以它不再是继承或者复制而是全新的创造。 四、孤儿进程与僵尸进程
1、父进程和子进程的关系 一个父进程可以创建多个子进程但每个子进程最多只能有一个父进程。整个系统中只有一个根进程即 PID 为 0 的调度进程。系统中的所有进程构成了一棵以调度进程为根的进程树。 2、父进程和子进程之间的区别 fork 的返回值不同子进程返回 0 而父进程返回新建子进程 ID。 进程 ID 不同 这两个进程的父进程 ID 不同子进程的父进程 ID 是创建它的进程的 ID而父进程的父进程 ID 则不变。 子进程的tms_utime , tms_stime , tms_cutime以及tms_ustime设置为0。 子进程不继承父进程设置的文件锁。 子进程的未处理闹钟被清除。 子进程的未处理信号集设置为空集。 3、孤儿进程 父进程创建子进程以后子进程在操作系统的调度下与其父进程同时运行。如果父进程先于子进程终止子进程即成为孤儿进程同时被 init 进程收养即成为 init 进程的子进程因此 inti 进程又被成为孤儿院进程。 #include stdio.h
#include unistd.h
#include stdlib.hint main (void)
{pid_t pid;if ((pid fork ()) 0)perror (fork), exit (1);else if (pid 0){sleep (3); // 子进程被暂停三秒所以当父进程退出后子进程仍然未退出。printf (这是子进程 pid %d, getpid ());printf (父进程的 ppid %d\n, getppid ());}else {printf (这是父进程 ppid %d\n, getpid ());}return 0;
}
4、僵尸进程 如果子进程先于父进程终止但父进程由于某种原因没有回收子进程的退出状态子进程即成为僵尸进程。 僵尸进程虽然已经不再活动但其终止状态仍然保留也会占用系统资源直到被其父进程回收才得以释放。 如果父进程直到终止都未回收它的已成僵尸的子进程init 进程会立即收养并回收这些处于僵尸状态的子进程因此一个进程不可能既是孤儿进程同时又是僵尸进程。 一个进程成为僵尸进程需要引起注意如果它的父进程长期运行而不终止僵尸进程所占用的资源将长期得不到释放。 #include stdio.h
#include stdlib.h
#include unistd.hint main (void)
{pid_t pid;pid fork ();if (pid -1)perror (fail to fork), exit (1);else if (pid 0){printf (这是子进程 pid %d, getpid ());printf (父进程的 ppid %d\n, getppid ());}else{// 父进程休眠了十秒而在这期间子进程已经退出了//子进程就形成了一段时间的僵尸进程。sleep (10); printf (这是父进程 ppid %d\n, getpid ());}return 0;
}