并发程序设计1:多进程并发

在并发程序设计中,主要有三种并发方式:多进程并发,基于IO复用并发,多线程并发。本节主要介绍多进程并发。以多客户端ehco程序为例。

1.  进程

       进程是具有独立功能的程序关于某个数据集合的一次运行活动,是OS为正在运行的程序建立的管理实体,是系统资源管理与分配的基本单位。一个进程有五部分:操作系统管理该进程的数据结构(PCB),内存代码,内存数据,程序状态字PSW,通用寄存器信息。一个进程在OS中有四个基本状态。如图1.1所示。

          

                   图1.1 进程四态

挂起:挂起是OS收回进程的所有资源,将其移出内存。

创建进程时,实际上OS为其建立一个进程控制块,用于保存该进程的信息。多个进程同时运行时,其在内存中的状态如图1.2所示。

 

           图1.2 多进程的内核状态

2. 多进程并发

        进程是程序运行的基本单位,对于多内核的计算机,多个进程可以在多内核上同时运行,提高程序的并发性。如对于C/S类型的模型,客户端每发起一次通信,服务器开辟一个进程于其连接。这样实现服务器同时服务多个客户端。以经典的回声服务器,客户端为例,讲解多进程并发(注:Windows系统不支持,相关代码均以Linux系统为例)。

  Linux系统的每个进程都有一个标志号,称为进程ID,其值大于2(1要分配给系统启动后的首个进程,用于协助操作系统)。在Linux系统中,创建一个进程采用fork函数

#include <unistd.h>
pid_t fork(void);  //pid_t为返回的ID号

调用fork函数之后,子进程创建,子进程会复制父进程的所有信息,然后从fork调用之后开始执行。那么怎么让父子进程执行不同的程序路径呢?这是通过主程序判断实现的,父进程调用fork函数,返回的是子进程的ID;而子进程的fork函数返回0,通过此返回值区别父子进程,从而控制fork函数之后的执行流。

2.1 僵尸进程

  父进程fork子进程后,两个进程按各自的程序执行。父子进程结束时通过以下两种操作返回值并结束。

(1) 通过调用return语句返回;

(2) 通过exit()函数返回。

此返回值会保存至OS。但是子进程结束后,其返回值返回给操作系统(OS),此时OS并不会回收分配给子进程的所有资源。所以当父进程没执行完而子进程执行完成时,子进程资源没被回收,此时的子进程即为僵尸进程。僵尸进程会造成系统资源浪费。那么什么时候子进程资源会被回收呢?

(1) 当父进程结束之后;

(2) 当父进程向OS请求子进程返回值时。

因此为了结束僵尸进程,需要父进程主动向OS请求子进程的返回值。通过以下两种方式实现:

(1)父进程结束之前调用wait()函数

#include <sys/wait.h>

int status; //保存返回时的状态信息
wait(&status);
if(WIFEXITED(status))//WIFEXITED()在子进程正常终止时返回真
    printf("Child return:%d",WEXITSTATUS(status)); //WEXITSTATUS获取子进程的返回值

一般有父进程创建了几个子进程就需要调用几次wait函数。调用wait函数后,父进程将阻塞直到有结束的子进程。

(2) 调用waitpid()

#include <sys/wait.h>

pid_t waitpid(pid_t pid,int* statloc,int options);
pid:等待的进程ID,若-1,则等待任一进程终止
statloc:用于保存返回状态的变量,与wait函数的参数一致
options:一般传递WNOHANG,意为非阻塞。

waitpid为非阻塞状态。

2.2 

猜你喜欢

转载自www.cnblogs.com/yuanwebpage/p/12361275.html