Linux线程池在server上简单应用
一、问题描写叙述
如今以C/S架构为例。client向server端发送要查找的数字,server端启动线程中的线程进行对应的查询。将查询结果显示出来。
二、实现方案
1. 整个project以client、server、lib组织。例如以下图所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3poaWNoZW5nMTk4Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
2. 进入lib。
socket.h、socket.c
- /**
- @file socket.h
- @brief Socket API header file
- TCP socket utility functions, it provides simple functions that helps
- to build TCP client/server.
- @author wangzhicheng
- */
- #ifndef SOCKET_H
- #define SOCKET_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <resolv.h>
- #include <fcntl.h>
- #define MAX_CONNECTION 20
- int TCPServerInit(int port, int *serverfd);
- int TCPServerWaitConnection(int serverfd, int *clientfd, char *clientaddr);
- int TCPServerSelect(int* serverfdlist, int num, int *clientfd, char *clientaddr);
- int TCPClientInit(int *clientfd);
- int TCPClientConnect(const int clientfd, const char *addr, int port);
- int TCPNonBlockRead(int clientfd, char* buf, int size);
- int TCPBlockRead(int clientfd, char* buf, int size);
- int TCPWrite(int clientfd, char* buf, int size);
- void TCPClientClose(int sockfd);
- void TCPServerClose(int sockfd);
- #endif
socket.c
- #include "socket.h"
- /*
- * @brief initialize TCP server
- * @port port number for socket
- * @serverfd server socket fd
- * return server socked fd for success, on error return error code
- * */
- int TCPServerInit(int port, int *serverfd) {
- struct sockaddr_in dest;
- // create socket , same as client
- *serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if(*serverfd < 0) return -1;
- /// initialize structure dest
- memset((void*)&dest, '\0', sizeof(dest));
- dest.sin_family = PF_INET;
- dest.sin_port = htons(port);
- dest.sin_addr.s_addr = INADDR_ANY;
- // Assign a port number to socket
- bind( *serverfd, (struct sockaddr*)&dest, sizeof(dest));
- return *serverfd;
- }
- /*
- * @brief wait client connect
- * @serverfd server socket fd
- * @clientfd client socket fd
- * @clientaddr client address which connect to server
- * return client fd, on error return error code
- * */
- int TCPServerWaitConnection(int serverfd, int *clientfd, char *clientaddr) {
- struct sockaddr_in client_addr;
- socklen_t addrlen = sizeof(client_addr);
- // make it listen to socket
- listen( serverfd, 20);
- // Wait and Accept connection
- *clientfd = accept(serverfd, (struct sockaddr*)&client_addr, &addrlen);
- strcpy( clientaddr, (const char *)( inet_ntoa( client_addr.sin_addr)));
- return *clientfd;
- }
- /*
- * @brief initialize TCP client
- * @clientfd client socket fd
- * return client socked fd for success, on error return error code
- */
- int TCPClientInit(int *clientfd) {
- *clientfd = socket(PF_INET, SOCK_STREAM, 0);
- return *clientfd;
- }
- /*
- * @brief connect to TCP server
- * @clientfd client socket fd
- * @addr server address
- * @port server port number
- * return 0 for success, on error -1 is returned
- */
- int TCPClientConnect(const int clientfd, const char *addr, int port) {
- struct sockaddr_in dest;
- // initialize value in dest
- memset(&dest, '\0', sizeof(dest));
- dest.sin_family = PF_INET;
- dest.sin_port = htons(port);
- inet_aton(addr, &dest.sin_addr);
- // Connecting to server
- return connect(clientfd, (struct sockaddr*)&dest, sizeof(dest));
- }
- /*
- * @brief non-block read from TCP socket
- * @clientfd socket fd
- * @buf input buffer
- * @size buffer size
- * return the length of read data
- */
- int TCPNonBlockRead(int clientfd, char* buf, int size) {
- int opts;
- opts = fcntl(clientfd, F_GETFL);
- opts = (opts | O_NONBLOCK);
- fcntl(clientfd, F_SETFL, opts);
- return recv(clientfd, buf, size, 0);
- }
- /*
- * @brief block read from TCP socket
- * @clientfd socket fd
- * @buf input buffer
- * @size buf size
- * return the length of read data
- */
- int TCPBlockRead(int clientfd, char* buf, int size) {
- int opts;
- opts = fcntl(clientfd, F_GETFL);
- opts = (opts & ~O_NONBLOCK);
- fcntl(clientfd, F_SETFL, opts);
- return recv(clientfd, buf, size, 0);
- }
- /*
- * @brief write to TCP socket
- * @clientfd socket fd
- * @buf output buf
- * @size output buf length
- * return the length of the actual written data, -1: disconnected
- */
- int TCPWrite(int clientfd, char* buf, int size) {
- int len= 0;
- /* set socket to nonblock */
- int ret = fcntl(clientfd, F_GETFL);
- ret |= O_NONBLOCK;
- if (fcntl(clientfd, F_SETFL, ret) < 0 ) {
- printf("set socket to nonblock fail [%d] !\n", errno);
- }
- len = send(clientfd, buf, size, MSG_NOSIGNAL);
- return len;
- }
- /*
- * @brief close the tcp connection
- * @sockfd socket fd
- * return none
- */
- void TCPConnectionClose(int sockfd) {
- close(sockfd);
- }
threadpool.h
- #ifndef THREADPOOL_H
- #define THREADPOOL_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <unistd.h>
- struct job
- {
- void* (*callback_function)(void *arg); //线程回调函数
- void *arg; //回调函数參数
- struct job *next;
- };
- struct threadpool
- {
- int thread_num; //线程池中开启线程的个数
- int queue_max_num; //队列中最大job的个数
- struct job *head; //指向job的头指针
- struct job *tail; //指向job的尾指针
- pthread_t *pthreads; //线程池中全部线程的pthread_t
- pthread_mutex_t mutex; //相互排斥信号量
- pthread_cond_t queue_empty; //队列为空的条件变量
- pthread_cond_t queue_not_empty; //队列不为空的条件变量
- pthread_cond_t queue_not_full; //队列不为满的条件变量
- int queue_cur_num; //队列当前的job个数
- int queue_close; //队列是否已经关闭
- int pool_close; //线程池是否已经关闭
- };
- //================================================================================================
- //函数名: threadpool_init
- //函数描写叙述: 初始化线程池
- //输入: [in] thread_num 线程池开启的线程个数
- // [in] queue_max_num 队列的最大job个数
- //输出: 无
- //返回: 成功:线程池地址 失败:NULL
- //================================================================================================
- struct threadpool* threadpool_init(int thread_num, int queue_max_num);
- //================================================================================================
- //函数名: threadpool_add_job
- //函数描写叙述: 向线程池中加入任务
- //输入: [in] pool 线程池地址
- // [in] callback_function 回调函数
- // [in] arg 回调函数參数
- //输出: 无
- //返回: 成功:0 失败:-1
- //================================================================================================
- int threadpool_add_job(struct threadpool *pool, void* (*callback_function)(void *arg), void *arg);
- //================================================================================================
- //函数名: threadpool_destroy
- //函数描写叙述: 销毁线程池
- //输入: [in] pool 线程池地址
- //输出: 无
- //返回: 成功:0 失败:-1
- //================================================================================================
- int threadpool_destroy(struct threadpool *pool);
- //================================================================================================
- //函数名: threadpool_function
- //函数描写叙述: 线程池中线程函数
- //输入: [in] arg 线程池地址
- //输出: 无
- //返回: 无
- //================================================================================================
- void* threadpool_function(void* arg);
- #endif
threadpool.c
- #include "threadpool.h"
- struct threadpool* threadpool_init(int thread_num, int queue_max_num) {
- struct threadpool *pool = NULL;
- do
- {
- pool = malloc(sizeof(struct threadpool));
- if (NULL == pool)
- {
- printf("failed to malloc threadpool!\n");
- break;
- }
- pool->thread_num = thread_num;
- pool->queue_max_num = queue_max_num;
- pool->queue_cur_num = 0;
- pool->head = NULL;
- pool->tail = NULL;
- if (pthread_mutex_init(&(pool->mutex), NULL))
- {
- printf("failed to init mutex!\n");
- break;
- }
- if (pthread_cond_init(&(pool->queue_empty), NULL))
- {
- printf("failed to init queue_empty!\n");
- break;
- }
- if (pthread_cond_init(&(pool->queue_not_empty), NULL))
- {
- printf("failed to init queue_not_empty!\n");
- break;
- }
- if (pthread_cond_init(&(pool->queue_not_full), NULL))
- {
- printf("failed to init queue_not_full!\n");
- break;
- }
- pool->pthreads = malloc(sizeof(pthread_t) * thread_num);
- if (NULL == pool->pthreads)
- {
- printf("failed to malloc pthreads!\n");
- break;
- }
- pool->queue_close = 0;
- pool->pool_close = 0;
- int i;
- for (i = 0; i < pool->thread_num; ++i)
- {
- pthread_create(&(pool->pthreads[i]), NULL, threadpool_function, (void *)pool);
- }
- return pool;
- } while (0);
- return NULL;
- }
- int threadpool_add_job(struct threadpool* pool, void* (*callback_function)(void *arg), void *arg) {
- if(pool == NULL || callback_function == NULL || arg == NULL) return -1;
- pthread_mutex_lock(&(pool->mutex));
- while ((pool->queue_cur_num == pool->queue_max_num) && !(pool->queue_close || pool->pool_close))
- {
- pthread_cond_wait(&(pool->queue_not_full), &(pool->mutex)); //队列满的时候就等待
- }
- if (pool->queue_close || pool->pool_close) //队列关闭或者线程池关闭就退出
- {
- pthread_mutex_unlock(&(pool->mutex));
- return -1;
- }
- struct job *pjob =(struct job*) malloc(sizeof(struct job));
- if (NULL == pjob)
- {
- pthread_mutex_unlock(&(pool->mutex));
- return -1;
- }
- pjob->callback_function = callback_function;
- pjob->arg = arg;
- pjob->next = NULL;
- if (pool->head == NULL)
- {
- pool->head = pool->tail = pjob;
- pthread_cond_broadcast(&(pool->queue_not_empty)); //队列空的时候,有任务来时就通知线程池中的线程:队列非空
- }
- else
- {
- pool->tail->next = pjob;
- pool->tail = pjob;
- }
- pool->queue_cur_num++;
- pthread_mutex_unlock(&(pool->mutex));
- return 0;
- }
- void* threadpool_function(void* arg) {
- struct threadpool *pool = (struct threadpool*)arg;
- struct job *pjob = NULL;
- while (1) //死循环
- {
- pthread_mutex_lock(&(pool->mutex));
- while ((pool->queue_cur_num == 0) && !pool->pool_close) //队列为空时,就等待队列非空
- {
- pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));
- }
- if (pool->pool_close) //线程池关闭,线程就退出
- {
- pthread_mutex_unlock(&(pool->mutex));
- pthread_exit(NULL);
- }
- pool->queue_cur_num--;
- pjob = pool->head;
- if (pool->queue_cur_num == 0)
- {
- pool->head = pool->tail = NULL;
- }
- else
- {
- pool->head = pjob->next;
- }
- if (pool->queue_cur_num == 0)
- {
- pthread_cond_signal(&(pool->queue_empty)); //队列为空,就能够通知threadpool_destroy函数,销毁线程函数
- }
- if (pool->queue_cur_num == pool->queue_max_num - 1)
- {
- pthread_cond_broadcast(&(pool->queue_not_full)); //队列非满。就能够通知threadpool_add_job函数,加入新任务
- }
- pthread_mutex_unlock(&(pool->mutex));
- (*(pjob->callback_function))(pjob->arg); //线程真正要做的工作,回调函数的调用
- free(pjob);
- pjob = NULL;
- }
- }
- int threadpool_destroy(struct threadpool *pool) {
- if(pool == NULL) return -1;
- pthread_mutex_lock(&(pool->mutex));
- if (pool->queue_close || pool->pool_close) //线程池已经退出了,就直接返回
- {
- pthread_mutex_unlock(&(pool->mutex));
- return -1;
- }
- pool->queue_close = 1; //置队列关闭标志
- while (pool->queue_cur_num != 0)
- {
- pthread_cond_wait(&(pool->queue_empty), &(pool->mutex)); //等待队列为空
- }
- pool->pool_close = 1; //置线程池关闭标志
- pthread_mutex_unlock(&(pool->mutex));
- pthread_cond_broadcast(&(pool->queue_not_empty)); //唤醒线程池中正在堵塞的线程
- pthread_cond_broadcast(&(pool->queue_not_full)); //唤醒加入任务的threadpool_add_job函数
- int i;
- for (i = 0; i < pool->thread_num; ++i)
- {
- pthread_join(pool->pthreads[i], NULL); //等待线程池的全部线程运行完成
- }
- pthread_mutex_destroy(&(pool->mutex)); //清理资源
- pthread_cond_destroy(&(pool->queue_empty));
- pthread_cond_destroy(&(pool->queue_not_empty));
- pthread_cond_destroy(&(pool->queue_not_full));
- free(pool->pthreads);
- struct job *p;
- while (pool->head != NULL)
- {
- p = pool->head;
- pool->head = p->next;
- free(p);
- }
- free(pool);
- return 0;
- }
3.进入client
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3poaWNoZW5nMTk4Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
client.c
- /*************************************************************************
- > File Name: test.c
- > Author: wangzhicheng
- > Mail: 2363702560@qq.com
- > Created Time: Fri 03 Oct 2014 09:43:59 PM WST
- ************************************************************************/
- #include "socket.h"
- const char * serveraddr = "127.0.0.1";
- #define TCPPORT 4001
- int main() {
- int clientfd = -1;
- char buf[256];
- strcpy(buf, "1");
- if(TCPClientInit(&clientfd) < 0) {
- perror("client init failed...!\n");
- exit(EXIT_FAILURE);
- }
- if(TCPClientConnect(clientfd, serveraddr, TCPPORT)) {
- perror("can not connect to server...!\n");
- exit(EXIT_FAILURE);
- }
- if(TCPWrite(clientfd, buf, strlen(buf) == 1)) {
- printf("send successfully...!\n");
- }
- else printf("send failed...!\n");
- return 0;
- }
Makefile
- CC=gcc
- LIBRARY=../lib
- CFLAGS=-I$(LIBRARY)
- CXXFLAGS=
- OBJS1=client.o socket.o
- all: client
- client: $(OBJS1)
- $(CC) -o $@ $(OBJS1)
- socket.o: $(LIBRARY)/socket.c
- $(CC) -c $(LIBRARY)/socket.c
- clean:
- rm *.o client > /dev/null 2>&1
4. 进入server
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3poaWNoZW5nMTk4Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
server.c
- /*************************************************************************
- > File Name: server.c
- > Author: ma6174
- > Mail: ma6174@163.com
- > Created Time: Sat 04 Oct 2014 09:46:30 PM WST
- ************************************************************************/
- #include "socket.h"
- #include "threadpool.h"
- #define TCPPORT 4001
- #define SIZE 256
- #define N 10
- int array[N] = {1, 2, 6, 8, 12, 88, 208, 222, 688, 1018};
- int find(int low, int high, int m) {
- int mid;
- if(low <= high) {
- mid = (low + high) >> 1;
- if(array[mid] == m) return 1;
- else if(array[mid] > m) return find(low, mid - 1, m);
- else return find(mid + 1, high, m);
- }
- return 0;
- }
- void* work(void* arg)
- {
- int *p = (int *) arg;
- int m = *p;
- if(find(0, N - 1, m)) printf("%d has been found...!\n", m);
- else printf("%d has not been found...!\n", m);
- sleep(1);
- }
- int main() {
- int serverfd = -1, clientfd = -1;
- char clientaddr[SIZE];
- char buf[SIZE];
- int num;
- struct threadpool *pool = NULL;
- TCPServerInit(TCPPORT, &serverfd);
- if(serverfd < 0) {
- perror("server init failed...!\n");
- exit(EXIT_FAILURE);
- }
- pool = threadpool_init(10, 20);
- while(1) {
- TCPServerWaitConnection(serverfd, &clientfd, clientaddr);
- if(clientfd < 0) {
- perror("can not connect the clients...!\n");
- exit(EXIT_FAILURE);
- }
- if(TCPBlockRead(clientfd, buf, SIZE) <= 0) {
- perror("can not read from client...!\n");
- sleep(1);
- }
- else {
- num = atoi(buf);
- threadpool_add_job(pool, work, &num);
- }
- }
- threadpool_destroy(pool);
- return 0;
- }
Makefile
- CC=gcc
- LIBRARY=../lib
- CFLAGS=-I$(LIBRARY)
- CXXFLAGS=
- OBJS1=server.o socket.o threadpool.o
- all: server
- server: $(OBJS1)
- $(CC) -o $@ $(OBJS1) -lpthread
- socket.o: $(LIBRARY)/socket.c
- $(CC) -c $(LIBRARY)/socket.c
- threadpool.o: $(LIBRARY)/threadpool.c
- $(CC) -c $(LIBRARY)/threadpool.c
- clean:
- rm *.o client > /dev/null 2>&1
三、測试
四、有关线程池的说明
当线程池被创建时,线程池中有些“空”的线程。即不运行任务,每当一个任务被增加进来时,任务就被组织成任务队列,线程依照队列队头出。队尾进的原则取出头任务运行。
任务队列中所含任务数必须控制在一个上限内。超过上限时。任务被堵塞。当全部任务被运行完,销毁线程池。
Linux线程池在server上简单应用的更多相关文章
- 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量
线程池的含义跟它的名字一样,就是一个由许多线程组成的池子. 有了线程池,在程序中使用多线程变得简单.我们不用再自己去操心线程的创建.撤销.管理问题,有什么要消耗大量CPU时间的任务通通直接扔到线程池里 ...
- python线程池ThreadPoolExecutor(上)(38)
在前面的文章中我们已经介绍了很多关于python线程相关的知识点,比如 线程互斥锁Lock / 线程事件Event / 线程条件变量Condition 等等,而今天给大家讲解的是 线程池ThreadP ...
- linux线程池thrmgr源码解析
linux线程池thrmgr源码解析 1 thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2 ...
- 一个简单的linux线程池(转-wangchenxicool)
线程池:简单地说,线程池 就是预先创建好一批线程,方便.快速地处理收到的业务.比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高. 在linux中,使用的 ...
- Linux下线程池的理解与简单实现
首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...
- 关于C#线程,线程池和并行运算的简单使用和对比
转自:https://www.cnblogs.com/jeffwongishandsome/archive/2010/11/12/1876137.html 先大概看一下控制台应用程序的Main方法的主 ...
- 【Android】线程池原理及Java简单实现
线程池简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力. 假设一个服务器完成一项任务所需时间为: T1 创建线程时间 T2 在线程中 ...
- linux线程池
typedef struct task_node { void *arg; /* fun arg. */ void *(*fun) (void *); /* the real work of the ...
- Linux线程池的实现
线程池的实现 1:自定义封装的条件变量 //condition.h #ifndef _CONDITION_H_ #define _CONDITION_H_ #include <pthread.h ...
随机推荐
- drupal 8——在CKEditor中导入video media时添加caption会导致video缩小至消失
在CKEditor中,我点击media browser,选择video型的media,并在caption中输入video的名字.当我保存后发现在前台页面的video消失了,只留下video的名字,点击 ...
- 《Java编程的逻辑》第二部分 面向对象
- jQuery——尺寸位置
获取宽:$(".box").width() 设置宽:$(".box").width(200) 获取高:$(".box").height() ...
- JS——dom
节点的获取 <script> var div = document.getElementById("box");//返回指定标签 var div = document. ...
- 3星|《腾讯产业森林:AI时代的创业密码》:后半部分是较详细的创业指南,前面泛泛介绍腾讯、AI
腾讯产业森林:AI时代的创业密码 前半部分泛泛介绍腾讯对创业者的支持,腾讯支持的创业项目的案例.AI的一些基本介绍,后半部分是比较详细的写给创业者的各阶段行动与选择的指南. 总体评价3星,有一些参考价 ...
- 在Windows下安装Elasticsearch5.0
1.准备工作 安装和配置Java环境 2.下载 地址:https://www.elastic.co/downloads/elasticsearch 老版本:https://www.elastic.co ...
- NFS指定端口,NFS缓存(转载)
nfs服务端: #编辑/etc/nfsmount.conf,在末尾添加: #RQUOTAD_PORT=30001#LOCKD_TCPPORT=30002#LOCKD_UDPPORT=30002#MOU ...
- php中fopen不能创建中文文件名文件的问题
之前网页的chartset用的是utf-8,文件也用utf-8,然后用fopen()创建一个中文文件名的文件时问题就出来了,文件名都是乱 码! 查看了很多文档试了不少方法都解决不了,本来想着用别的方法 ...
- 02. 爬取get请求的页面数据
目录 02. 爬取get请求的页面数据 一.urllib库 二.由易到难的爬虫程序: 02. 爬取get请求的页面数据 一.urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用 ...
- opencv图像阈值设置的三种方法
1.简单阈值设置 像素值高于阈值时,给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色).这个函数就是 cv2.threshhold().这个函数的第一个参数就是原图像 ...