Linux下的进程池(1)

简介

基于Linux的进程池的实现,并发进程池有多种实现模式,在这里统一进行分析。首先给出客户端的测试代码:

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <wait.h>

const int clientNum = 10;   // 创建用户个数
const int nloop = 100;      // 每个用户动态创建连接个数
static int cnt = 0;

void sig_handler (int sig) {
    if (sig != SIGCHLD) {
        return;
    }
    pid_t pid;
    while ( (pid = waitpid (-1, NULL, WNOHANG) ) > 0) {
        printf ("child process: %d left\n", pid);
        ++cnt;
    }
    if (cnt >= clientNum) {
        puts ("all clients end...");
        exit (0);
    }
}


int main (int argc, char* argv[]) {
    if (argc != 3) {
        printf ("Usage: %s <ip of server> <port of server>\n", argv[0]);
        exit (0);
    }

    int port = atoi (argv[2]);
    if (port < 1024 || port > 65535) {
        perror ("port error\n");
        exit (0);
    }

    struct sockaddr_in serv;
    bzero (&serv, sizeof (serv) );
    if (inet_pton (AF_INET, argv[1], &serv.sin_addr) == -1) {
        perror ("inet_pton() error\n");
        exit (1);
    }
    serv.sin_family = AF_INET;
    serv.sin_port = htons (port);

    struct sigaction sa;
    bzero (&sa, sizeof (sa) );
    sa.sa_handler = sig_handler;
    sa.sa_flags = SA_RESTART;
    if (sigaction (SIGCHLD, &sa, NULL) < 0) {
        perror ("sigaction() error");
    }

    for (int i = 0; i < clientNum; ++i) {
        pid_t pid;
        if ( (pid = fork() ) == 0) {  // 孩子进程
            int fd = socket (AF_INET, SOCK_STREAM, 0);
            if (fd < 0) {
                perror ("socket() error\n");
                exit (1);
            }
            if (connect (fd, (struct sockaddr*) &serv, sizeof (serv) ) < 0) {
                perror ("connect() error\n");
                exit (1);
            }
            const char* buf = "Hello world !\n";

            for (int j = 0; j < nloop; ++j) {
                send (fd, buf, strlen (buf), 0);
            }

            close (fd);
            printf ("client %d end...\n", i);
            exit (0);
        }
    }

    while (true) {
        sleep (1);
    }

    exit (0);
}

这里介绍的是使用不带锁的accept结构的进程池。原理是:如果有多个accept函数等待监听内核中同一个fd,那么没有数据时都阻塞。如果有数据,那么所有的都会被唤醒,但是只能有一个进程获取fd,其余的唤醒后接着休眠。这种结构简单,但是出现线程池“惊群”现象,这里的唤醒和休眠会浪费大量的时间,并发度高的时候,更是如此。但是对于少量并发的情况,还是比较合适的,给出代码实现:

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>
#include <wait.h>

const int MAX_PROCESS_NUMBER = 15;
const int MAX_BUFFER_SIZE = 1024;

bool stop_server = false;
pid_t* pids = nullptr;
int processNum = 0;

void sig_int (int signo);   // 终止整个线程池
void process (int fd);  // 子进程处理连接
pid_t child_make (int fd);  // 产生新的子进程
void child_main (int fd);   // 子进程的主要操作

int main (int argc, char* argv[]) {
    if (argc != 3) {
        printf ("Usage: %s <port of server> <number of process>\n", argv[0]);
        exit (0);
    }

    int port = atoi (argv[1]);
    if (port < 1024 || port > 65535) {
        perror ("port error\n");
        exit (0);
    }

    processNum = atoi (argv[2]);
    if (processNum < 0 || processNum > MAX_PROCESS_NUMBER) {
        perror ("process number error\n");
        exit (0);
    }

    struct sockaddr_in serv;
    bzero (&serv, sizeof (serv) );
    serv.sin_family = AF_INET;
    serv.sin_port = htons (port);
    serv.sin_addr.s_addr = htonl (INADDR_ANY);

    int listenfd = socket (AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) {
        perror ("socket() error\n");
        exit (1);
    }

    if (bind (listenfd, (struct sockaddr*) &serv, sizeof (serv) ) < 0) {
        perror ("bind() error\n");
        exit (1);
    }

    if (listen (listenfd, 32) < 0) {
        perror ("listen() error\n");
        exit (1);
    }

    struct sigaction sa;  // 注册终止信号
    bzero (&sa, sizeof (sa) );
    sa.sa_handler = sig_int;
    sa.sa_flags = SA_RESTART;
    if (sigaction (SIGTERM, &sa, NULL) < 0) {
        perror ("sigaction() error\n");
        exit (1);
    }

    pids = new pid_t[processNum];
    for (int i = 0; i < processNum; ++i) {
        pids[i] = child_make (listenfd);
    }

    while (!stop_server) {
        sleep (1);
    }

    exit (0);
}

void sig_int (int signo) {
    if (signo != SIGTERM) {
        return;
    }
    for (int i = 0; i < processNum; ++i) {
        kill (pids[i], SIGTERM); // 终止子进程
    }
    if (pids != nullptr) {
        delete[] pids;
    }
    stop_server = true;
}

pid_t child_make (int fd) {
    pid_t pid;
    if ( (pid = fork() ) > 0) {
        return pid;
    }

    child_main (fd);
}

void child_main (int fd) {
    struct sockaddr_in address;
    bzero (&address, sizeof (address) );
    socklen_t addrlen = sizeof (address);

    for (;;) {
        int connfd = accept (fd, (struct sockaddr*) &address, &addrlen);
        if (connfd < 0) {
            return;
        }
        puts ("accept data");
        process (connfd);
        close (fd);
    }
}

void process (int fd) {
    char buf[MAX_BUFFER_SIZE];
    for (;;) {
        if (recv (fd, buf, MAX_BUFFER_SIZE, 0) <= 0) {
            return;
        }
        printf ("%s", buf);
    }
}
好的,以下是一个简单的 Linux C 语言进程筛素数的实现方式: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #define N 1000 // 筛选 1~N 的素数 // 筛素数的函数 void sieve(int n, int *primes) { int i, j; int is_prime; primes[0] = primes[1] = 0; for (i = 2; i <= n; i++) { is_prime = 1; for (j = 2; j < i; j++) { if (i % j == 0) { is_prime = 0; break; } } primes[i] = is_prime; } } // 进程中的子进程,根据起始和结束下标筛素数 void worker(int start, int end, int *primes) { int i, j; int is_prime; for (i = start; i <= end; i++) { is_prime = 1; for (j = 2; j < i; j++) { if (i % j == 0) { is_prime = 0; break; } } primes[i] = is_prime; } } int main() { int num_processes = 4; // 进程数 int primes[N + 1]; // 存储素数信息的数组 int i, j; pid_t pid; int start, end; // 初始化 primes 数组 for (i = 0; i <= N; i++) { primes[i] = 1; } // 创建进程 for (i = 0; i < num_processes; i++) { start = i * (N / num_processes) + 1; end = (i + 1) * (N / num_processes); if (i == num_processes - 1) { end = N; } pid = fork(); if (pid == 0) { worker(start, end, primes); exit(0); } } // 等待所有子进程执行完毕 for (i = 0; i < num_processes; i++) { wait(NULL); } // 输出素数 for (i = 2; i <= N; i++) { if (primes[i] == 1) { printf("%d ", i); } } printf("\n"); return 0; } ``` 该程序首先创建一个长度为 `N+1` 的整型数组 `primes`,用于存储 1~N 的素数信息。然后创建一个进程,每个子进程负责筛选一部分素数。具体来说,每个子进程根据自己的起始和结束下标,从中筛选素数,将素数信息存储在 `primes` 数组中。最后,主进程遍历 `primes` 数组,输出素数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值