1、进程控制进程控制进程控制理论基础进程控制理论基础进程控制编程进程控制编程.定义定义 进程是一个具有一定独立功能的程序的进程是一个具有一定独立功能的程序的一次运行活动一次运行活动。.特点特点动态性动态性并发性并发性独立性独立性异步性异步性.状态状态.进程进程ID进程进程ID(PID):标识进程的唯一数字:标识进程的唯一数字父进程的父进程的ID(PPID)启动进程的用户启动进程的用户ID(UID).进程互斥进程互斥进程互斥是指当有若干进程都要使用某进程互斥是指当有若干进程都要使用某一共享资源时,任何时刻最多允许一个一共享资源时,任何时刻最多允许一个进程使用,其他要使用该资源的进程必进程使用,其他要
2、使用该资源的进程必须等待,直到占用该资源者释放了该资须等待,直到占用该资源者释放了该资源为止。源为止。.临界资源临界资源 操作系统中将一次只允许一个进程访问操作系统中将一次只允许一个进程访问的资源称为临界资源。的资源称为临界资源。.临界区临界区进程中访问临界资源的进程中访问临界资源的那段程序代码那段程序代码称称为临界区。为实现对临界资源的互斥访为临界区。为实现对临界资源的互斥访问,应保证诸进程互斥地进入各自的临问,应保证诸进程互斥地进入各自的临界区。界区。.进程同步进程同步 一组一组并发进程按并发进程按一定的顺序一定的顺序执行的过程执行的过程称为进程间的同步。具有同步关系的一组称为进程间的同步
3、。具有同步关系的一组并发进程称为合作进程,合作进程间互相并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件。发送的信号称为消息或事件。.进程调度进程调度概念:概念:按一定算法,从一组待运行的进程中选出按一定算法,从一组待运行的进程中选出一个来占有一个来占有CPU运行。运行。调度方式:调度方式:抢占式抢占式非抢占式非抢占式.调度算法调度算法先来先服务调度算法先来先服务调度算法短进程优先调度算法短进程优先调度算法高优先级优先调度算法高优先级优先调度算法时间片轮转法时间片轮转法.死锁死锁 多个进程因竞争资源而形成一种僵局,多个进程因竞争资源而形成一种僵局,若无外力作用,这些进程都将永远不能
4、再若无外力作用,这些进程都将永远不能再向前推进。向前推进。.获取获取ID#include#includepid_t getpid(void)获取本进程获取本进程ID。pid_t getppid(void)获取父进程获取父进程ID。.获取获取ID#include#include#includeint main(void)printf(PID=%dn,getpid();printf(PPID=%dn,getppid();return 0;.进程创建进程创建#includepid_t fork(void)功能:功能:创建子进程创建子进程fork的奇妙之处在于它被调用一的奇妙之处在于它被调用一次,却返
5、回两次,它可能有三种不同的返回值:次,却返回两次,它可能有三种不同的返回值:1.在父进程中,在父进程中,fork返回新创建的子进程的返回新创建的子进程的PID;2.在子进程中,在子进程中,fork返回返回0;3.如果出现错误,如果出现错误,fork返回一个负值返回一个负值.进程创建进程创建#include#inlcudemain()pid_t pid;/*此时仅有一个进程此时仅有一个进程*/pid=fork();/*此时已经有两个进程在同时运行此时已经有两个进程在同时运行*/if(pid0)printf(error in fork!);else if(pid=0)printf(I am the
6、 child process,ID is%dn,getpid();elseprintf(I am the parent process,ID is%dn,getpid();?执行后的结果?执行后的结果?.进程创建进程创建$./fork_testI am the parent process,my process ID is 1991I am the child process,my process ID is 1992 在在pid=fork()之前,只有一个进程在执行,但在这条语之前,只有一个进程在执行,但在这条语句执行之后,就变成两个进程在执行了,这两个进程的句执行之后,就变成两个进程在执行
7、了,这两个进程的代码部分完全相同,代码部分完全相同,将要执行的下一条语句都是将要执行的下一条语句都是f(pid=0)。两个进程中,原先就存在的那个进程被称。两个进程中,原先就存在的那个进程被称作作“父进程父进程”,新出现的那个进程被称作,新出现的那个进程被称作“子进程子进程”,父子父子进程的区别在于进程标识符(进程的区别在于进程标识符(PID)不同。)不同。.进程创建进程创建思考运行结果?思考运行结果?#include#includeint main(void)pid_t pid;int count=0;count+;pid=fork();printf(This is first time,p
8、id=%dn,pid);printf(This is second time,pid=%dn,pid);count+;printf(count=%dn,count);if(pid0)printf(This is parent process,the child has the pid:%dn,pid);else if(!pid)printf(This is the child process.n);elseprintf(fork failed.n);printf(This is third time,pid=%dn,pid);printf(This is fouth time,pid=%dn,
9、pid);return 0;.进程创建进程创建思考运行结果?思考运行结果?父进程的数据空间、堆栈空间都会给子进父进程的数据空间、堆栈空间都会给子进程一个拷贝,而不是共享这些内存。在子程一个拷贝,而不是共享这些内存。在子进程中对进程中对count进行自加进行自加1的操作,但是并的操作,但是并没有影响到父进程中的没有影响到父进程中的count值,父进程值,父进程中的中的count值仍然为值仍然为0。.进程创建进程创建#include#includepid_t vfork(void)功能:创建子进程。功能:创建子进程。.创建进程创建进程区别:区别:1.fork要拷贝父进程的数据段;而要拷贝父进程的数
10、据段;而vfork则则不需要完全拷贝父进程的数据段,子进程不需要完全拷贝父进程的数据段,子进程与父进程共享数据段。与父进程共享数据段。2.fork不对父子进程的执行次序进行任何限不对父子进程的执行次序进行任何限制;而在制;而在vfork调用中,子进程先运行,调用中,子进程先运行,父进程挂起。父进程挂起。.进程创建进程创建1.#include2.#include3.#include4.main()5.int count=1;6.int child;7.8.printf(“Before create son,the fathers count is:%dn”,count);9.if(!(child
11、=vfork()10.11.printf(This is son,his pid is:%d and the count is:%dn,getpid(),+count);12.exit(1);13.else14.printf(After son,This is father,his pid is:%d and the count is:%d,and the child is:%dn,getpid(),count,child);15.16.执行程序执行程序exec用用被执行的程序被执行的程序替换替换调用它的程序调用它的程序。区别:区别:fork创建一个新的进程,产生一个新的创建一个新的进程,产生
12、一个新的PID。exec启动一个新程序,替换原有的进程,启动一个新程序,替换原有的进程,因此进程的因此进程的PID不会改变,和调用不会改变,和调用exec函函数的进程一样。数的进程一样。.执行程序执行程序#includeint execl(const char*path,const char*arg,.)功能:功能:运行参数运行参数path所指定的可执行文件,接下所指定的可执行文件,接下来的参数代表执行该文件时传递过去的来的参数代表执行该文件时传递过去的argv0、argv1,最后一个参数必须,最后一个参数必须用空指针用空指针(NULL)作结束。作结束。.执行程序执行程序#includemai
13、n()execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char*)0);.执行程序执行程序#includeint execlp(const char*file,const char*arg,)功能:功能:从从PATH环境变量所指的目录中查找符合参数环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的第二个以后的参数当做该文件的argv0、argv1,最后一个参数必须用空指针,最后一个参数必须用空指针(NULL)作结束。作结束。.执行程序执行程序#includemain()
14、execlp(”ls”,”ls”,”-al”,”/etc/passwd”,(char*)0);.执行程序执行程序#includeint execv(const char*path,char*const argv)功能:功能:执行参数执行参数path所指定的文件,与所指定的文件,与execl()不同的不同的地方在于地方在于execve()只需两个参数,第二个参数只需两个参数,第二个参数利用数组指针来传递给执行文件。利用数组指针来传递给执行文件。.执行程序执行程序#includemain()char*argv=“ls”,”-al”,”/etc/passwd”,(char*)0;execv(“/bi
15、n/ls”,argv);.执行程序执行程序#includeint system(const char*string)功能:功能:调用调用fork()产生子进程,由子进程来调用产生子进程,由子进程来调用/bin/sh-c string来执行参数来执行参数string字符串字符串所代表的命令。所代表的命令。.执行程序执行程序includemain()system(“ls-al/etc/passwd /etc/shadow”);.等待等待#include#includepid_t wait(int*status)功能:功能:进程一旦调用了进程一旦调用了wait,就立即阻塞自己,直到自,就立即阻塞自己
16、,直到自己的己的某个某个子进程退出,如果没有找到这样一个子子进程退出,如果没有找到这样一个子进程,进程,wait就会一直阻塞在这里,直到有一个出就会一直阻塞在这里,直到有一个出现为止。现为止。.等待等待#include#include#include#includemain()pid_t pc,pr;pc=fork();if(pc0)/*如果出错如果出错*/printf(error ocurred!n);else if(pc=0)/*如果是子进程如果是子进程*/printf(This is child process with pid of%dn,getpid();sleep(10);/*睡眠
17、睡眠10秒钟秒钟*/else/*如果是父进程如果是父进程*/pr=wait(NULL);/*在这里等待在这里等待*/printf(I catched a child process with pid of%dn),pr);exit(0);.等待等待#include#includepid_t waitpid(pid_t pid,int*status,int options)功能:功能:进程一旦调用了进程一旦调用了wait,就立即阻塞自己,直到自,就立即阻塞自己,直到自己的己的某个某个子进程退出,如果没有找到这样一个子子进程退出,如果没有找到这样一个子进程,进程,wait就会一直阻塞在这里,直到有
18、一个出就会一直阻塞在这里,直到有一个出现为止。现为止。.等待等待当当pid取不同的值时,有不同的意义:取不同的值时,有不同的意义:1.pid0时,只等待进程时,只等待进程ID等于等于pid的子进程,不管其它已的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还经有多少子进程运行结束退出了,只要指定的子进程还没有结束,没有结束,waitpid就会一直等下去。就会一直等下去。2.pid=-1时,等待任何一个子进程退出,没有任何限制,时,等待任何一个子进程退出,没有任何限制,此时此时waitpid和和wait的作用一模一样。的作用一模一样。3.pid=0时,等待同一个进程组中的任何子
19、进程。时,等待同一个进程组中的任何子进程。4.pid-1时,等待一个指定进程组中的任何子进程,这个时,等待一个指定进程组中的任何子进程,这个进程组的进程组的ID等于等于pid的绝对值。的绝对值。.等待等待参数参数option可以为可以为0或下面的或下面的OR组合组合:WNOHANG:如果没有任何已经结束的子进程则马上返如果没有任何已经结束的子进程则马上返回回,不予以等待。不予以等待。WUNTRACED:如果子进程进入暂停执行情况则马上返回。如果子进程进入暂停执行情况则马上返回。.发送信号发送信号#include#includeint kill(pid_t pid,int sig)功能:功能:发
20、送参数发送参数sig指定的信号给参数指定的信号给参数pid指定的进程指定的进程pid0将信号传给进程识别码为将信号传给进程识别码为pid的进程的进程pid=0将信号传给和目前进程相同进程组的所有进程将信号传给和目前进程相同进程组的所有进程pid=-1将信号广播传送给系统内所有的进程将信号广播传送给系统内所有的进程pid0将信号传给进程组识别码为将信号传给进程组识别码为pid绝对值的所有进程绝对值的所有进程.退出退出exit和和_exit用于中止进程用于中止进程:_exit的作用:直接使进程停止运行,清除其的作用:直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的数据结使用的内存空间,并清除其在内核中的数据结构。构。exit与与_exit函数不同,使进程停止运行之前要函数不同,使进程停止运行之前要检查文件打开情况,并把文件缓冲区的内容写检查文件打开情况,并把文件缓冲区的内容写回文件中去之后才停止进程。回文件中去之后才停止进程。.