线程池

线程池

      服务器启动则创建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操作
	}
}

线程池