进程控

进程的控制大概包括进程创建、进程执行和进程终止,附加有进程的属性。

进程标识符

每个进程都有一个唯一的ID,它是一个非负整数。进程ID可以重用,当进程终止后,UNIX一般通过延迟重用算法,使得赋予新进程的ID不同于最近终止进程的ID。

系统中有些专用ID。ID为0的通常是调度进程,也被称为交换进程(swapper),它是内核的一部分,不执行磁盘上的任何程序,也被称为系统进程。ID为1的通常是init进程,在自举过程结束时由内核调用,它负责读写系统有关的初始化文件,并将系统引导到一个状态,但它不会终止;它是普通进程,但是以超级用户特权运行,它负责收留孤儿进程。ID为2的进程是页守护进程,负责支持虚拟系统的分页操作。

fork函数

fork函数可以创建新进程,新创建的为子进程。fork函数调用一次,返回两次。两次返回的唯一区别就是其返回值,在子进程中,其返回值为0,而在父进程中,返回值为子进程的ID。这样做的目的是一个进程子进程可以有多个,但是父进程无法获取子进程ID,但是子进程父进程只有一个,可以调用函数getppid获得父进程ID。

子进程创建后,复制了父进程的数据空间、堆、栈,但是共享代码段。现代操作系统通常并不是马上复制,而是使用了写时复制(copy-on-write,COW)。但是不是父进程所有资源都被继承,父进程的文件锁不会被继承,子进程的未处理的闹钟被清除,子进程未处理的信号集设置为空。

在调用fork后,父进程和子进程谁先执行是不确定的,取决于内核使用的调度算法。如果要求父进程、子进程同步,则要使用某种形式的进程间通信了。

在使用fork时通常有2中用法

1、父进程希望复制自己,使父子进程执行不同的代码。比如在网络服务中,父进程等待客户端请求,当请求到达时,创建子进程执行此请求,而父进程继续等待。

2、一个进程要执行一个不同的程序。比如在shell中,子进程创建后立即调用exec函数。

vfork函数

它与fork的不同在于vfork不复制进程的地址空间,它创建子进程的目的是为了执行新的程序,如果复制了也会被覆盖,浪费资源。vfork调用后子进程先运行,直到子进程调用exec函数或exit函数后,父进程才运行。

exit函数

之前已经讲过,进程正常终止有5中方式

1、在main函数返回,相当于调用exit

2、调用exit

3、调用_exit或_Exit

4、进程的最后一个线程在其启动的历程中执行返回语句。

5、进程的最后一个线程调用pthread_exit

进程异常终止有3种方式

1、调用abort,它产生SIGABRT信号,这是下一种异常终止的特例

2、进程接收到某些信号时

3、最后一个线程对“取消”(cancellation)请求做出响应

不过进程如何终止,都会执行同一段代码:为相应的进程关闭所有打开的文件描述符,释放所使用的存储器等。

不管进程如何终止,我们都希望进程可以通知其父进程它是如何终止的。exit、_exit、_Exit将其退出状态作为参数传送给函数。异常终止情况下,内核产生一个指示其异常终止原因的终止状态,其父进程可以调用wait或waitpid取得终止状态。

进程异常终止后,其终止状态信息包括进程ID、进程终止状态、进程使用CPU时间总量。如果其父进程还没处理终止状态信息,那么这个进程就叫做僵死进程(zombie)。如果父进程先于子进程终止,那么init进程就会领养它。

wait和waitpid函数

当一个进程终止时(正常或异常)内核会向其父进程发送SIGCHLD信号。父进程可以选择忽略,也可以提供一个信号处理程序来处理子进程。这里有一个博客参考。

如果编写信号处理程序的话,一般用到wait和waitpid函数。如果调用这两个函数会发生:

如果子进程还在运行,则阻塞

如果一个子进程已经终止,正等待父进程获得其终止状态,则取得子进程的终止状态立即返回。

如果没有子进程,则立即出错返回。

两个函数原型如下:

#include<sys/wait.h>

pid_t wait(int *statloc);

pid_t wait(pid_t pid, int *statloc, int options);

后者选项比较多,更加灵活。

exec函数

子进程可以调用exec函数执行另一个程序。当调用exec函数时,进程执行的程序完全被替换为新程序,但其ID并不变,只是用新程序替换了当前进程的正文、数据、堆和栈段。

exec函数共有六种:

#include <unistd.h>

int execl(const char *path, const char *arg, ...);

int execv(const char *path, char *const argv[]);

int execle(const char *path, const char *arg, ..., char * const envp[]);

int execve(const char *path, char *const argv[], char *const envp[]);

int execlp(const char *file, const char *arg, ...);

int execvp(const char *file, char *const argv[]);

这些函数看起来相似。第一个参数都是在寻找可执行文件,第二个参数是传递的参数,其中l表示list,v表示vector。这些函数其实都是调用一个函数execve

时间: 2024-07-30 13:45:09

进程控的相关文章

MFC非模态添加进程控件方法一(线程方法)

由于非模态对话框的自己没有消息循环,创建后无法进行消息处理.需要和父窗口共用消息循环.如果单独在子窗口进行控件由于自己没有单独的消息循环,更新是无法进行的. 如果在父窗口更新控件会造成程序假死.如以下代码在主窗口更新子窗口消息,界面进入假死状态.因为主界面对主进程进行了sleep(100),如下代码所示 void CModelessDlg::OnBnClickedOk() { DLGModeLess *pDlg = new DLGModeLess(); pDlg->Create(IDD_DG_M

多进程 (二) — 信号传递与进程控

内容目录: multiprocessing.Queue() JoinableQueue 进程间的信号传递 Event 控制对资源的访问 Lock 同步操作 Condition 控制对资源的并发访问 Semaphore 管理共享状态 Manager 共享命名空间 mgr.Namespace() 进程池 multiprocessing.Pool 1. multiprocessing.Queue() 和线程一样,多进程的一个常见的使用模式是将一个任务划分为几个worker,以便并行运行.有效地使用多进

20135302魏静静——linux课程第八周实验及总结

linux课程第八周实验及总结 实验及学习总结 1. 进程切换在内核中的实现 linux中进程切换是很常见的一个操作,而这个操作是在内核中实现的. 实现的时机有以下三个时机: 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule(): 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度: 用户

测试应该都学些什么!

记得从上学那会.初中的时候老师还是会让大家做些笔记.初中毕业后.高中甚至大学就一直很少在写个人笔记了.至少我是哈.主动承认自己的不足. 为什么要说笔记呢.原因很简单.就是最近工作出现的一连串繁琐事情.当然不排除我个人认为笔记有时候很好的描述一个人的成长历练.经历等等. 话题跑偏了好像.先说一下笔记的好处: 1.做笔记是训练一个人的语言转化能力 2.做笔记可以提高一个人选择.归纳有效信息的能力. 文章的主题是测试应该学习些神马?我本人也是做测试的.从毕业截止到今.不多不少2年半. 刚开始的时候做这

Linux内核分析期末总结

<Linux内核分析>期末总结 20135313吴子怡.北京电子科技学院 Chapter1 往期博客传送门 (1)计算机是如何工作的:Linux内核分析——第一周学习笔记 (2)操作系统是如何工作的:Linux内核分析——第二周学习笔记 (3)Linux系统启动过程:Linux内核分析——第三周学习笔记 (4)系统调用的方法: Linux内核分析——第四周学习笔记 Linux内核实验作业四 (5)分析system_call中断处理过程: Linux内核分析——第五周学习笔记 实验作业:使gdb

在Linux下线程死锁的四个条件

一.死锁的原因和必要条件 1.死锁的概念 一般情况下,如果同一个线程先后两次调用lock,在第一次调用时,由于锁已经被占,该线程会挂起等待别的线程释放锁,然而锁正是被自己占着的,该线程又被挂起,没有机会释放锁,因此,就永远处于挂起等待状态了,这叫做死锁(Deadlock).另种典型的死锁情形是这样:线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永

linux学习之进程,线程和程序

                                                                                  程序.进程和线程的概念 1:程序和进程的差别 进程的出现最初是在UNIX下,用于表示多用户,多任务的操作系统环境下,应用程序在内存环境中基本执行单元的概念.进程是UNIX操作系统环境最基本的概念.是系统资源分配的最小单位.UNIX操作系统下的用户管理和资源分配等工作几乎都是操作系统通过对应用程序进程的控制实现的! 当使用c c++ j

线程及与进程的对比

一.为什么要引入线程 进程是为了提高CPU的执行效率,减少因程序等待带来的CPU空转以及其他计算机软硬件资源而提出来的.进程是一个资源拥有者,因而在进程的创建.撤消和切换中,系统必须为之付出较大的时空开销.也正因为如此,在系统中所设置的进程数目不宜过多,进程切换的频率也不宜太高,但这也就限制了并发程度的进一步提高.如何能使多个程序更好地并发执行,同时又尽量减少系统的开销,已成为近年来设计操作系统时所追求的重要目标.于是,有不少操作系统的学者们想到,可否将进 程的上述属性分开,由操作系统分开来进行

进程与线程的一个复杂解释

关于进程和线程,面试的时候被问了两次都没有答出来.第一次问完稍微看了下概念,并没有完全理解所以也没有记住,所以第二次被问到的时候也没回答出来o(╯□╰)o.. 所以这次把这个问题彻底解决一下. 标题是模仿阮一峰大大的"进程与线程的一个简单解释",见http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html,里面比喻得很形象. 定义 进程(英语:process),是计算机中已运行程序的实体.进程为曾经是分时系统的基本