进程池的学习

来源:互联网 发布:ug8.5编程步骤 编辑:程序博客网 时间:2024/05/16 13:52
一   进程的概念主要有两点:


第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。


第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。


进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。


操作系统引入进程的概念的原因:


从理论角度看,是对正在运行的程序过程的抽象;


从实现角度看,是一种数据结构,目的在于清晰地刻划动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。










进程池是资源进程,管理进程组成的应用


进程池中的应用至少由以下两部分组成:
1资源进程:预先创建好空闲的进程,管理进程会把工作分配到空闲进程来处理。
2管理进程:负责创建资源进程,把工作交给资源进程处理,回收已经处理完的资源进程。


管理进程要有效的管理资源进程,那么管理进程跟资源进程间必然需要交互,通过IPC,信号,信号量,消息队列,管道等进行交互。


进程池是由服务器预先创建的一组子进程,这些子进程的数目在3~10个之间(当然这只是典型情况)。线程池中的线程数量应该和CPU数量差不多。




进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、PGID等。




当有新的任务来到时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务。相比于动态创建子进程,选择一个已经存在的子进程的代价显得小得多。至于主进程选择哪个子进程来为新任务服务,则有两种方法:




主进程使用某种算法来主动选择子进程。最简单、最常用的算法是随机算法和Round Robin(轮流算法)。
主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有新的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程将获得新任务的“接管权”,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上。




当选择好子进程后,主进程还需要使用某种通知机制来告诉目标子进程有新任务需要处理,并传递必要的数据。最简单的方式是,在父进程和子进程之间预先建立好一条管道,然后通过管道来实现所有的进程间通信。在父线程和子线程之间传递数据就要简单得多,因为我们可以把这些数据定义为全局,那么它们本身就是被所有线程共享的。




多进程并发服务器代码




TCP 并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是由服务器创建一个子进程来处理。
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>                         
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>      
  
int main(int argc, char *argv[])  
{  
    unsigned short port = 8080;     // 本地端口   
  
    //1.创建tcp套接字  
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);     
    if(sockfd < 0)  
    {  
        perror("socket");  
        exit(-1);  
    }  
      
    //配置本地网络信息  
    struct sockaddr_in my_addr;  
    bzero(&my_addr, sizeof(my_addr));     // 清空     
    my_addr.sin_family = AF_INET;         // IPv4  
    my_addr.sin_port   = htons(port);     // 端口  
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip  
      
    //2.绑定  
    int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));  
    if( err_log != 0)  
    {  
        perror("binding");  
        close(sockfd);        
        exit(-1);  
    }  
      
    //3.监听,套接字变被动  
    err_log = listen(sockfd, 10);   
    if(err_log != 0)  
    {  
        perror("listen");  
        close(sockfd);        
        exit(-1);  
    }  
      
    while(1) //主进程 循环等待客户端的连接  
    {  
          
        char cli_ip[INET_ADDRSTRLEN] = {0};  
        struct sockaddr_in client_addr;  
        socklen_t cliaddr_len = sizeof(client_addr);  
          
        // 取出客户端已完成的连接  
        int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);  
        if(connfd < 0)  
        {  
            perror("accept");  
            close(sockfd);  
            exit(-1);  
        }  
          
        pid_t pid = fork();  
        if(pid < 0){  
            perror("fork");  
            _exit(-1);  
        }else if(0 == pid){ //子进程 接收客户端的信息,并发还给客户端  
            /*关闭不需要的套接字可节省系统资源, 
              同时可避免父子进程共享这些套接字 
              可能带来的不可预计的后果 
            */  
            close(sockfd);   // 关闭监听套接字,这个套接字是从父进程继承过来  
          
            char recv_buf[1024] = {0};  
            int recv_len = 0;  
              
            // 打印客户端的 ip 和端口  
            memset(cli_ip, 0, sizeof(cli_ip)); // 清空  
            inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);  
            printf("----------------------------------------------\n");  
            printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));  
              
            // 接收数据  
            while( (recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0 )  
            {  
                printf("recv_buf: %s\n", recv_buf); // 打印数据  
                send(connfd, recv_buf, recv_len, 0); // 给客户端回数据  
            }  
              
            printf("client_port %d closed!\n", ntohs(client_addr.sin_port));  
            close(connfd);    //关闭已连接套接字  
            exit(0);  
              
        }  
        else if(pid > 0){    // 父进程  
            close(connfd);    //关闭已连接套接字  
        }  
    }  
      
    close(sockfd);  
      
    return 0;  
}