一个简单线程池的实现 --C语言

本文的代码实现了一个简单的线程池,并利用C/S模型将客户端所发送的数据进行简单的计算。

一:什么是线程池

  我是这么理解的,池是计算机科学中一种典型的机制,如STL里面的内存池,数据库连接池,还有进程池或线程池。这些池建立的目的都是为了避免频繁系统调用所带来的开销。我们这样想,如果我们事先转备好一大块所需要的内存,或者线程,以后我们要用到时就直接拿来用就好了。不够的话再执行其他解决方案。

二:本文代码线程池实现细节

  在本文代码中,定义了一个线程池线程数组,线程池水深(线程数)假定为5,这个值我们根据实际情况选择。我们可以事先申请5个线程,让他们在各自的线程运行函数内部循环,这就相当于block,但不是block。当我们需要线城时,直接拿来主义,让该线程的WORK_STATE为BUSY态,这是全局结构体变量,当检测到此情况出现,线程run,这就是线程池的分配过程。

  线程池回收,将BUSY态改为IDLE态即可,继续循环。

  如果线程池不够用,我对额外线程采用的机制是,来一个申请一个,走一个销毁一个。

三:头文件

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdbool.h>

#define INIT_THREAD_NUM 5
#define MAXLINE 1024
#define err_quit(m) \
		do{ \
			perror(m); \
			exit(1); \
		}while(0)

typedef enum{IDLE, BUSY}WORK_STATE;
typedef enum{ADD, SUB, MUL, DIV, MOD}OPER_ENUM;
typedef struct {
	int       op1;
	int       op2;
	OPER_ENUM oper;
}oper_struct;

四:服务器代码

#include "../utili.h"

void math_operation(oper_struct *ptr, int *res);
static void* extra_thread_handler(void *arg);
static void* pool_thread_handler(void *arg);
bool find_idle_thread(int connfd);

typedef struct thread_extra {   
	int index;
	int connfd;
} thread_extra;    //额外线程结构体

typedef struct thread_pool {
	int        connfd;
	WORK_STATE state;
} thread_pool;     //线程池结构体
typedef thread_pool pool_array[INIT_THREAD_NUM];    //线程池线程数组

pool_array pool;
int extra_num;     //额外数目,用来计算额外线程序号

int main()
{
	int listenfd;
	struct sockaddr_in servaddr;

	if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_quit("socket err.\n");
	
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(6666);
	servaddr.sin_addr.s_addr = INADDR_ANY;

	int on = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	
	if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
		err_quit("bind err.\n");
	
	if(listen(listenfd, SOMAXCONN) < 0)
		err_quit("listen err.\n");
	
	int connfd;
	struct sockaddr_in clientaddr;
	socklen_t len = sizeof(clientaddr);
	pthread_t tid_array[INIT_THREAD_NUM];

	for(int i=0; i<INIT_THREAD_NUM; ++i){
		pthread_create(&tid_array[i], NULL, pool_thread_handler, &i);
		sleep(1);
	}

	for(int i=0; i<INIT_THREAD_NUM; ++i){
		pool[i].state = IDLE;
	}

	pthread_t tid;
	thread_extra th_extra;
	for(; ;){
		if( (connfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len)) < 0)
			err_quit("accept err.\n");
		else
			printf("client: IP:%s PORT:%d connect.\n", inet_ntoa(clientaddr.sin_addr),
													ntohs(clientaddr.sin_port));
		if(!find_idle_thread(connfd)){
			++extra_num;
			th_extra.index = INIT_THREAD_NUM + extra_num - 1;
			th_extra.connfd = connfd;
			pthread_create(&tid, NULL, extra_thread_handler, &th_extra);
		}
	}
	return 0;
}

bool find_idle_thread(int connfd)
{
	for(int i=0; i<INIT_THREAD_NUM; ++i){
		if(pool[i].state == IDLE){
			pool[i].state = BUSY;
			pool[i].connfd = connfd; 
			return true;
		}
	}
	return false;
}

static void* pool_thread_handler(void *arg)
{	
	pthread_detach(pthread_self());
	
	int index = *(int *)arg;
	printf("[%d] thread start up.\n", index);

	int         res;
	ssize_t     nrecv;
	oper_struct ops;
	for(; ;){
		for(; ;){
			if(pool[index].state == BUSY){
				printf("[%d] thread provide service.\n", index);
				if( (nrecv = recv(pool[index].connfd, &ops, sizeof(ops), 0)) == 0){
					printf("peer close,[%d] thread to have a rest.\n", index);
					break;
				}
			
				math_operation(&ops, &res);
				printf("the result is:%d\n", res);
				send(pool[index].connfd, &res, sizeof(res), 0);
			}
		}
		pool[index].state = IDLE;             //线程回收
		close(pool[index].connfd);
	}
	return (void *)0;
}

static void* extra_thread_handler(void *arg)
{
	pthread_detach(pthread_self());
	
	int index = *(int *)arg;
	int connfd = *((int *)arg+1);
	printf("[%d] thread start up.\n", index);
	
	int         res;
	ssize_t     nrecv;
	oper_struct ops;
	for(; ;){
		printf("[%d] thread provide service.\n", index);
		if( (nrecv = recv(connfd, &ops, sizeof(ops), 0)) == 0){
			printf("peer close,[%d] thread go to dead.\n", index);
			break;
		}
			
		math_operation(&ops, &res);
		printf("the result is:%d\n", res);
		send(connfd, &res, sizeof(res), 0);
	}
	--extra_num;
	close(connfd);
	
	return (void *)0;
}

void math_operation(oper_struct *ptr, int *res)
{
	switch(ptr->oper){
		case ADD:
			*res = ptr->op1 + ptr->op2;
			break;
		case SUB:
			*res = ptr->op1 - ptr->op2;
			break;
		case MUL:
			*res = ptr->op1 * ptr->op2;
			break;
		case DIV:
			*res = ptr->op1 / ptr->op2;
			break;
		case MOD:
			*res = ptr->op1 % ptr->op2;
			break;
		default: 
			break;
	}
}

五:客户端代码

#include "../utili.h"

void input_opernum(oper_struct *pointer);

int main()
{
	int sockfd;
	struct sockaddr_in servaddr;

	if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_quit("socket err.\n");
	
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(6666);
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
		err_quit("connect err.\n");
	
	oper_struct ops;
	char *symbol;
	char recvbuff[MAXLINE];
	for( ; ;){
		printf("please input operator symbol:>\n");
		scanf("%s", symbol);
		if(strncmp(symbol, "add", 3) == 0){
			ops.oper = ADD;
			input_opernum(&ops);
		}
		else if(strncmp(symbol, "sub", 3) == 0){
			ops.oper = SUB;
			input_opernum(&ops);
		}
		else if(strncmp(symbol, "mul", 3) == 0){
			ops.oper = MUL;
			input_opernum(&ops);
		}
		else if(strncmp(symbol, "div", 3) == 0){
			ops.oper = DIV;
			input_opernum(&ops);
		}
		else if(strncmp(symbol, "mod", 3) == 0){
			ops.oper = MOD;
			input_opernum(&ops);
		}
		else{
			printf("invilid input.\n");
			continue;
		}
		
		send(sockfd, &ops, sizeof(ops), 0);

		recv(sockfd, recvbuff, sizeof(int), 0);
		printf("the answer is:>%d\n", *(int*)recvbuff);
	}
	close(sockfd);

	return 0;
}

*所有程序均经过验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值