本文的代码实现了一个简单的线程池,并利用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;
}
*所有程序均经过验证。