线程池
线程池
服务器启动则创建n(固定值,有限值)个子进程或者函数线程,创建的子进程或函数线程在服务器终止时销毁,如果有客户端连接,则分配一个子进程或线程为其服务,服务完成之后则继续等待分配下一个客户端。
线程池比多线程的优势
1、创建的进程或者线程是有限的:服务器的系统代价比较小,一般不会达到系统限制的值。
2、服务器不需要顿繁的创建、销毁进程或线程,只在服务器启动时创建,结束时销毁。
3、创建的进程或者线程不是为一个客户端服务,可以串行为多个客户端服务。
4、客户端连接上以后,不需要再去创建进程或线程,只需要分配进程池或线程池中的进程或线程,对于客户端的速度就能快一些。
1、主线程和所有的函数线程同步执行通过信号量
2、线程通过信号量P操作阻塞在线程池中
3、如何分配一个线程为客户端服务? 主线程接受一个客户端连接执行V操作
4、主线程如何传递客户端连接的文件描述符?全局维护一个数组或链表
Sever
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <semaphore.h>
#define THREADNUM 3
#define CLIENTNUM 10
sem_t sem;
pthread_mutex_t mutex;
int ClientFds[CLIENTNUM];
void Init_ClientFds()
{
int i=0;
for(;i<CLIENTNUM;++i)
{
ClientFds[i]=-1;
}
}
void Insert_Client(int fd)
{
pthread_mutex_lock(&mutex);
int i=0;
for(;i<CLIENTNUM;i++)
{
if(ClientFds[i]==-1)
{
ClientFds[i]=fd;
break;
}
}
pthread_mutex_unlock(&mutex);
}
int Get_Client()
{
pthread_mutex_lock(&mutex);
int i=0,c=-1;
for(;i<CLIENTNUM;++i)
{
if(ClientFds[i]!=-1)
{
c=ClientFds[i];
ClientFds[i]=-1;
break;
}
}
pthread_mutex_unlock(&mutex);
return c;
}
void*DealClient(void *arg)
{
while(1)
{
sem_wait(&sem);
int c=Get_Client();
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n==0)
{
printf("client unlink\n");
close(c);
break;//要继续接收下一个连接
}
printf("n==%d: %s",n,buff);
send(c,"OK",2,0);
}
}
}
int main()
{
int listenfd=socket(AF_INET,SOCK_STREAM,0);
assert(-1!=listenfd);
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;
ser.sin_port=htons(6000);
inet_aton("127,0,0,1",(struct in_addr*)&ser.sin_addr);
int res=bind(listenfd,(struct sockaddr*)&ser,sizeof(ser));
assert(-1!=res);
listen(listenfd,5);
sem_init(&sem,0,0);
pthread_mutex_init(&mutex,NULL);
Init_ClientFds();
//创建线程池
int i=0;
for(;i<THREADNUM;++i)
{
pthread_t id;
int res=pthread_create(&id,NULL,DealClient,NULL);
assert(res==0);
}
while(1)
{
struct sockaddr_in cli;
int len=sizeof(cli);
int c=accept(listenfd,(struct sockaddr*)&cli,&len);
assert(c!=-1);
Insert_Client(c);//将c传递给函数线程
sem_post(&sem);//V操作
}
}