当前位置:   article > 正文

Linux服务器7 --- 多路IO复用+线程池服务端模型(高并发)分析_122090148

122090148

一、服务端特性概述
1、使用EPOLL模型在服务器中加入(网络IO监听,大量的监听能力)
EPOLL采用边缘触发模式(后话)

2、线程池模型进行并发处理业务(并发处理能力)
1)提高线程重用性(避免频繁创建销毁线程)。
2)线程管理能力较强(根据需求扩容缩减)。
3)预创建处理线程,可以更为及时有效地为客户端服务。

3、不要让处理线程与客户端绑定(影响并发),处理线程可以重用为不同的客户端服务。
4、不要让线程池与业务绑定,使用者自行定义实现业务并传递给线程池, 线程负责执行即可。

5、服务端任务传递采用生产者消费者模式(EPOLL生产者, 线程池消费者)。 生产者消费者模型采用条件变量完成线程控制(挂起与唤醒)。

6、管理者角色,负责对线程池进行监控, 完成线程控制(扩容与缩减)。

7、业务分类,可以根据不同网络IO就绪,制定不同的业务(当然也可以根据客户端协议制定业务)。

8、考虑线程安全,全局资源访问用互斥手段。

二、服务端处理流程分析
1、首先userA客户端去connect服务端,连接请求被epoll监听到,生产者是主控线程控制epoll,通过epoll模型监听到就绪并传递任务。serverfd绑定业务A(建立连接),clientfd绑定业务B(处理请求),serverfd就绪产生了业务A,生产者就会将业务A添加到投放到线程池的业务队列中,线程池一般会先预创建一些线程,这些线程都是消费者,一生产者,多消费者,消费者从业务队列里面取出业务,拿到业务以后去执行,比如某一消费者取到的是业务A,那么就会去建立连接(accept),然后将返回的新的clientfd添加到监听集合中。如果取到的是业务B,处理完以后反馈给客户端,如果某一时刻客户端异常退出,将其对应的网络IO从监听树中删除。

2、主控线程生产者,普通线程消费者,还有一个单独的线程是管理者,负责对线程池中的普通线程进行扩容和缩减,监管普通线程,线程池
线程的扩容和缩减条件,线程执行业务,线程被占用,一段时间内不能再执行其他业务,线程状态busy,没有任务线程状态就是idle,创建多少线程,就有多少线程存活,线程数量计数的时候一般不算生产者和管理者。扩容条件一,忙线程占存活线程数量的70%,扩容条件二,当前任务数量>=闲线程数量。缩减条件为闲线程是忙线程的倍数。
三、服务端模块分析

#include<SOCKET_API.h>
/* 服务端宏定义 */
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8000
#define BUFSIZE 1500
#define BACKLOG 128
#define TIMEOUT 2 //等待超时
#define IPSIZE 16
#define EPOLLSIZE 90000
#define TRUE 1
#define FALSE 0
#define THREAD_CODE 10 //扩容缩减量

int epfd; //监听树描述符
pthread_mutex_t busines_lock; //业务锁

/* 结构体定义 */
typedef struct{
   void * (*BUSINES_ADDR)(void *); //业务地址 函数指针 哪个业务
   void * BUSINES_ARG; //业务参数 socket
}busines_t; //业务类型
//业务传给线程处理

typedef struct{
   /*线程池阈值*/
   int thread_shutdown; //线程池开关0/1 , 根据开关决定是否结束线程池
   int thread_max; //线程最大值
   int thread_min; //线程最小值
   int thread_busy;//繁忙线程数
   int thread_alive; //有效线程数量
   int thread_exitcode; //用于线程缩减
   pthread_t * customer_tids; //消费者线程tid数组
   pthread_t manager_tid; //保存管理者线程tid

   busines_t * busines_queue; //保存业务的唤醒队列
   int b_front; //业务队列头索引
   int b_rear; //业务队列尾索引
   int b_max; //业务队列最大数
   int b_cur; //业务队列当前业务数

   pthread_mutex_lock thread_lock; //互斥锁
   pthread_cond_t not_full; //生产者条件变量
   pthread_cond_t not_empty; //消费者条件变量
}thread_pool_t; //线程池类型

/* 服务端模型模块分析 */

void thread_pool_error(const char * strerror , int exitcode , int errno);
//如果errno==0则是标准错误处理,如果errno>0则是线程函数错误处理  将错误处理分成两类

int thread_pool_net_init(void); //成功返回serverfd , 失败返回-1  //服务端网络初始化

int thread_pool_epoll_init(int Sockfd); //成功返回监听树描述符,失败返回-1  //服务端epoll初始化  且监听serverfd

thread_pool_t * thread_pool_create(int Max , int Min , int QueMax); //线程池创建初始化,成功返回线程池地址

int thread_pool_destroy(thread_pool_t *); //释放销毁线程池资源 

int thread_pool_epoll_listen(int epfd , thread_pool_t * p,int sockfd);//负责网络IO事件监听,辨别就绪并添加任务 producer

int thread_pool_add_busines(thread_pool_t * , busines_t); //生产者向线程池中添加业务

void * thread_pool_customer_job(void * arg); //消费者默认工作,创建时传递线程池参数 从任务队列中取任务

void * thread_pool_manager_job(void * arg); //管理者默认工作,创建时传递线程池参数 需要线程池中的阈值

int if_thread_alive(pthread_t); //测试一个线程是否存活 ? 返回0表示线程已经结束,1表示线程存活

void * BUSINES_ACCEPT(void * arg); //TCP连接业务

void * BUSINES_RESPONSE(void * arg); //业务处理
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/683802
推荐阅读
相关标签
  

闽ICP备14008679号