一、问题描写叙述

如今以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上简单应用的更多相关文章

  1. 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量

    线程池的含义跟它的名字一样,就是一个由许多线程组成的池子. 有了线程池,在程序中使用多线程变得简单.我们不用再自己去操心线程的创建.撤销.管理问题,有什么要消耗大量CPU时间的任务通通直接扔到线程池里 ...

  2. python线程池ThreadPoolExecutor(上)(38)

    在前面的文章中我们已经介绍了很多关于python线程相关的知识点,比如 线程互斥锁Lock / 线程事件Event / 线程条件变量Condition 等等,而今天给大家讲解的是 线程池ThreadP ...

  3. linux线程池thrmgr源码解析

    linux线程池thrmgr源码解析 1         thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2      ...

  4. 一个简单的linux线程池(转-wangchenxicool)

    线程池:简单地说,线程池 就是预先创建好一批线程,方便.快速地处理收到的业务.比起传统的到来一个任务,即时创建一个线程来处理,节省了线程的创建和回收的开销,响应更快,效率更高. 在linux中,使用的 ...

  5. Linux下线程池的理解与简单实现

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  6. 关于C#线程,线程池和并行运算的简单使用和对比

    转自:https://www.cnblogs.com/jeffwongishandsome/archive/2010/11/12/1876137.html 先大概看一下控制台应用程序的Main方法的主 ...

  7. 【Android】线程池原理及Java简单实现

    线程池简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力. 假设一个服务器完成一项任务所需时间为: T1 创建线程时间 T2 在线程中 ...

  8. linux线程池

    typedef struct task_node { void *arg; /* fun arg. */ void *(*fun) (void *); /* the real work of the ...

  9. Linux线程池的实现

    线程池的实现 1:自定义封装的条件变量 //condition.h #ifndef _CONDITION_H_ #define _CONDITION_H_ #include <pthread.h ...

随机推荐

  1. Nginx一个实现负载均衡的强大web server

    <转>nginx 这个轻量级.高性能的 web server 主要可以干两件事情: 〉直接作为http server(代替apache,对PHP需要FastCGI处理器支持): 〉另外一个 ...

  2. wait、notify、notifyAll实现线程间通信

    在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信.在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调 ...

  3. CF414B Mashmokh and ACM

    思路: dp. 实现: 1.O(n5/2) #include <iostream> #include <cstdio> using namespace std; ; ][]; ...

  4. UI开发模式对比:JSP、Android、Flex

    前一篇文章分析了Java平台下不同类型WEB框架对开发模式的影响,多数Java领域的WEB框架都是聚焦于服务端MVC的实现,这些框架对View的支持,通常是基于标准的JSP或类似JSP的模板技术如Fr ...

  5. sysbench测试阿里云ECS云磁盘的IOPS,吞吐量

    测试阿里云ECS 对象:在aliyun上买了一个ECS附加的云盘,使用sysbench测试云盘的IOPS和吞吐量 sysbench prepare 准备文件,10个文件,1个1G [root@iZwz ...

  6. [工具]ps

    ps 如果想看一个进程的启动时间,可以用lstart来看 [root@jiangyi02.sqa.zmf /home/ahao.mah] #ps -eo pid,lstart,etime,cmd |g ...

  7. Vector 二维数组 实现

    1.C++实现动态二维数组 int **p; p = ]; //注意,int*[10]表示一个有10个元素的指针数组 ; i < ; ++i) { p[i] = ]; } 2.利用指针数组实现二 ...

  8. (C/C++学习)6.数组指针和指针数组

    说明:int (*p)[4] 和 int *p[4](数组指针和指针数组),如果你是一个初学者,也许当你看到这两个名词的时候,已经懵了.其实,只要你理解了其中的含义.这两个名词对你来说会相当简单并且很 ...

  9. VS单元测试"未能加载文件或程序集,或它的某一个依赖项"

    Autofac.Core.DependencyResolutionException : An error occurred during the activation of a particular ...

  10. MySQL数据库操作(一)

    一.数据操作 1.显示数据库 show databases; 2.创建数据库 #utf- create database 数据库名称 default charset utf8 collate utf8 ...