文档章节

Linux下线程池的使用

NickWhite
 NickWhite
发布于 2017/03/23 20:10
字数 1509
阅读 38
收藏 0

学习Linux下并发编程,终于自己捯饬出了一个线程池,在这里分享一下。

新人发帖,写的可能不怎么样,欢迎大家批评指正,谢谢您点赞哟* *^_^* *。

》》头文件 pthpool.h

/*
@brief:线程池实现
*/
#ifndef PTHPOOL_H
#define PTHPOOL_H

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>

#include<pthread.h>


#define TRUE     1
#define FALSE     0


typedef struct args{//任务函数的参数结构体
int no;
}Arg;
Arg *ArgPack(int n);//将参数打包以便任务函数使用,使用时重写这个函数
void *Task(void *arg);//任务函数,使用时重写
    
typedef struct task_node{//任务节点
  void *arg;//任务函数参数
  void *(*task)(void *arg);//任务函数
  int doing;//任务执行状态 0未执行,1正在执行,-1执行完毕
  struct task_node *next;//指向下一任务节点
}TNODE,*P_TNODE;


typedef struct pthread_pool{//线程池
  int shutdown;//线程池状态 1关闭,0开启
  pthread_mutex_t mutex;//互斥量,防止资源竞争
  pthread_cond_t cond;//条件变量,用于唤醒线程
  pthread_t *pthid;//线程id
  int npth;//线程数
  int nact;//活跃线程数
  TNODE *tasks;//任务链表
}PTHPOOL,*P_PTHPOOL;

int TasklistAdd(PTHPOOL *pthpool,TNODE *p);//将任务节点加入线程池的任务链表
int TasklistDelete(PTHPOOL *pthpool,TNODE *p); //从线程池任务链表中删除当前节点

PTHPOOL *PthpoolInit(int npth);// 线程池创建和初始化

int PthpoolDestroy(PTHPOOL *pthpool);//线程池销毁

TNODE *MakeNode(Arg *arg,void *(*task)(void *arg));//组装任务节点
void *pthfun(void *arg);//线程函数

 

 


 
#endif

》》源文件1 pthpool.c:线程池的相关函数

#include"pthpool.h"
pthread_mutex_t imutex = PTHREAD_MUTEX_INITIALIZER;//互斥量
pthread_cond_t icond= PTHREAD_COND_INITIALIZER;//条件变量,这两个必须设为全局变量,否则编译器莫名其妙的报错,不知道为什么
PTHPOOL *PthpoolInit(int npth){//线程池初始化
    if(1024 < npth){
        printf("%s fail : Too many.You can change the limit here - FILE: %s LINE:%d.\n",__func__,__FILE__,__LINE__);
        return FALSE;
    }
    
    PTHPOOL *pthpool = (PTHPOOL *)malloc(sizeof(PTHPOOL));
    
    pthpool->shutdown = FALSE;
    pthpool->mutex = imutex;//设置互斥量
    pthpool->cond = icond;//设置条件变量
    pthpool->npth = 0;
    pthpool->pthid = (pthread_t *)malloc(npth*sizeof(pthread_t));//注意:线程ID是一个内核识别的编号,并不是一个int型的数据,申请内存时要留心
    int i;
    int ret;
    for(i = 0;i < npth;++i){
        ret = pthread_create(&pthpool->pthid[i],NULL,pthfun,(void *)pthpool);//创建线程
        if(0 != ret){
            printf("pthread_create the %d fail\n",i+1);
            continue;
        }
        ++pthpool->npth;//线程个数
    }
    pthpool->nact = 0;
    pthpool->tasks = NULL;
    return pthpool;
}

int PthpoolDestroy(PTHPOOL *pthpool){//销毁线程池
    if(NULL == pthpool){
        printf("%s fail: pthpool does not exist.\n",__func__);
        return FALSE;
    }
    int ret;
    if(0 == pthpool->nact && NULL == pthpool->tasks){
        pthpool->shutdown = TRUE;//线程池关闭标志位置1,唤醒线程线程将进入退出语句块
        int i;
        for(i = 0;i < pthpool->npth;i++){
            pthread_cond_broadcast(&pthpool->cond);//唤醒线程
            pthread_join(pthpool->pthid[i],NULL);//回收线程
                
        }
        printf("died %d\n",i);    
        free(pthpool->pthid);//空间回收
        pthpool->pthid = NULL;
        free(pthpool);
        pthpool = NULL;
    }
    else{
        printf("Please ensure first that all tasks have been finished.\n");
        return FALSE;
    }    
    return TRUE;
}

        
》》 源文件2 tasklist.c 任务链表的相关函数 

 

#include"pthpool.h"


int TasklistAdd(PTHPOOL *pthpool,TNODE *p){//添加任务,头插法
    if(NULL == pthpool){
        printf("%s fail: pthpool does not exist.\n",__func__);
        return TRUE;
    }
    if(NULL == p){
        printf("%s fail: task node does not exist.\n",__func__);
        return TRUE;
    }
    if(NULL == pthpool->tasks){
        pthpool->tasks = p;
    }
    else{
        TNODE *q = pthpool->tasks;
        pthpool->tasks = p;
        p->next = q;
        q = NULL;
    }
    p = NULL;
    return TRUE;
}

int TasklistDelete(PTHPOOL *pthpool,TNODE *p){//删除任务节点
    if(NULL == pthpool){
        printf("%s fail: pthpool does not exist.\n",__func__);
        return FALSE;
    }
    if(NULL == pthpool->tasks){
        printf("%s fail: tasklist is empty.\n",__func__);
        return FALSE;
    }
    if(NULL == p){
        printf("%s fail: task node does not exist.\n",__func__);
        return FALSE;
    }
    if(0 == p->doing){
        printf("%s fail: task is to do.\n",__func__);
        return FALSE;
    }    
    if(1 == p->doing){
        printf("%s fail: task is doing.\n",__func__);
        return FALSE;
    }
    if(p == pthpool->tasks){//头结点
        if(NULL == p->next){
            free(p);
            pthpool->tasks = NULL;
        }
        else{
            pthpool->tasks = p->next;
            p->next = NULL;
            free(p);
        }            
    }
    else{//非头结点
        TNODE *q = pthpool->tasks;
        while(q->next != p){
            q = q->next;
        }
        if(NULL == p->next){
            free(p);
        }
        else{
            q->next = p->next;
            p->next = NULL;
            free(p);
        }
        q = NULL;
    }
    p = NULL;
    return TRUE;
}    

》》源文件3 pthfun.c 线程与任务相关函数

#include"pthpool.h"

 

Arg *ArgPack(int n){//将任务的函数组装成一个结构体,并返回它的指针,用时重写
    Arg *args = malloc(sizeof(Arg));
    args->no = n;    
    return args;
}

void *Task(void *arg){//任务函数,用时重写
    Arg *args = (Arg *)arg;
    printf("%d\t",args->no);
    return (void *)TRUE;

}


TNODE *MakeNode(Arg *arg,void *(*task)(void *arg)){//组装任务节点,返回其指针
    void *varg = (void *)arg;
    TNODE *p = (TNODE *)malloc(sizeof(*p));

    p->arg = varg;
    p->task = task;
    p->doing = 0;
    p->next = NULL;
       return p;
}
    
void *pthfun(void *arg){//线程函数
    void *p_ret;
    int ret;
    
    PTHPOOL *pthpool = (PTHPOOL *)arg;//获取线程池的资源
    if(NULL == pthpool){
        printf("%s argument illegal, pthpool does not exsit.\n",__func__);
        return NULL;
    }
    while(1){
        pthread_mutex_lock(&pthpool->mutex);//上锁
        pthread_cond_wait(&pthpool->cond, &pthpool->mutex);    //休眠,等待被主线程唤醒
        if(TRUE == pthpool->shutdown){//如果线程池关闭,退出
            printf("I'm going to die.\n");
            pthread_mutex_unlock(&pthpool->mutex);
            pthread_exit(NULL); 
        }        
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//防止执行任务时线程被意外取消
        ++pthpool->nact;//线程活跃数加1,表明该线程活跃
        TNODE *mytask = pthpool->tasks;
        while(NULL != mytask && 1 == mytask->doing){//获取存在的未执行任务
            mytask = mytask->next;
        }
        if(NULL != mytask){//如果获得任务,执行之
            mytask->doing = 1;//标志任务正在执行,防止重复执行
            p_ret = mytask->task(mytask->arg);//执行任务函数
            if((void *)FALSE == p_ret){
                printf("a task failed.\n");
            }
            mytask->doing = -1;//标志任务已经完成,节点可被销毁
            TasklistDelete(pthpool,mytask);//销毁该任务节点
        }    
        --pthpool->nact;//线程活跃数减1,线程将重新休眠
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//可能被取消
        pthread_mutex_unlock(&pthpool->mutex);//解锁
    }
}
        

》》源文件4 main.c 一个简单的测试程序

   #include"pthpool.h"
int main(){//一个简单的测试程序,将233打印100次
    PTHPOOL *pthpool = PthpoolInit(5);//线程池创建和初始化
    int x = 233;
    int n = 0;
    int i;
    while(n<100){
        Arg *arg = ArgPack(x);//参数打包
        TNODE *p = MakeNode(arg,Task);//组装节点
        TasklistAdd(pthpool,p);//将节点加入任务链表,一般的是添加一个任务就唤醒一个线程,这里恰巧没有这样做而已
        n++;        
    }
    printf("n = %d\n",n);
    while(pthpool->tasks){
        while(pthpool->nact == pthpool->npth);//如果线程全部活跃,将阻塞在这里;
        pthread_cond_signal(&pthpool->cond);
    }
    printf("\n");
    PthpoolDestroy(pthpool);
}

》》Makefile文件  

TARGET := PTHREAD_POOL
CSRCS := $(wildcard *.c)   #找通配规则为 *.c 的所有文件名
CSRCS += $(wildcard ./sub/*.c)
#OBJS := main.o a.o b.o c.o d.o 20150813.o
OBJS := $(patsubst  %.c, %.o, $(CSRCS))

CC := gcc

LIBS += -lpthread    #链接线程库

$(TARGET): $(OBJS)
    $(CC)  -o $@  $+  $(CFLAGS) $(LIBS)

%.o:%.c
    $(CC) -c $< -o $@ $(CFLAGS)
    
clean:
    rm  $(TARGET) $(OBJS)


  

 

写的也就这样了,新人发帖,欢迎大家指正!!*^_^* !!
    

   

   

 

 

   
    

© 著作权归作者所有

上一篇: C语言限定字
NickWhite
粉丝 0
博文 4
码字总数 1509
作品 0
长沙
程序员
私信 提问
Linux多线程并发服务器编程(线程池,FTP服务器)

分享网盘下载:https://pan.baidu.com/s/1gfNCcXt 密码: irfk 内容简介 本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握linux多线程网络编程技术,并...

人气王子333
2018/06/26
0
0
基于Linux/C++简单线程池的实现 我们知道Java语言对于多线程的支持十分丰富

我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等。C++11中的STL也提供了std:thread(然而我还没有看,这...

shzwork
04/24
0
0
读Apache的一点心得体会

曾经读过n多个开源的代码,包括linux内核,apache,openssl,memcache,libevent,vsftpd,xinetd等等其 中我最喜欢的就是linux内核了,除了linux内核排第二的就是apache,本文我就把欣赏的心...

晨曦之光
2012/04/10
345
0
LCP 1.0.0 版正式发布,Linux 连接池

Linux 连接池 LCP 1.0.0 正式发布,请大家多多关注,多语言,多服务,经过大量测试,效果非常明显,对于无状态的连接速度提升尤其明显。 LCP是Linux Connection Pool的简写,是基于Linux模块...

xilongtao
2015/10/27
2.1K
15
Java线程池中线程的状态简介

首先明确一下线程在JVM中的各个状态(JavaCore文件中) 1.死锁,Deadlock(重点关注) 2.执行中,Runnable(重点关注) 3.等待资源,Waiting on condition(重点关注) 4.等待监控器检查资源,...

IT夜行狼
2015/03/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Guava RateLimiter + AOP注解实现单机限流、统计QPS

1、基于springboot项目pom.xml添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency><d......

铁骨铮铮
24分钟前
3
0
龙芯版办公软件下载

金山wps office   rpm包:http://ftp.loongnix.org/os/loongnix/1.0/os/Packages/w/wps-office-10.8.0.6472-1.a20p1.mips64el.rpm   deb包:http://packages.deepin.com/loongson/pool/......

gugudu
29分钟前
2
0
BI报表分析和数据可视化,推荐这三个开源工具!

开源篇 一、Superset 1、技术架构:Python + Flask + React + Redux + SQLAlchemy 2、使用人群: (1)开发/分析人员做好看板,业务人员浏览看板数据 (2)业务人员可自行编辑图表,查看满足...

飓风2000
36分钟前
1
0
CountDownLatch

CountDownLatch的概念 CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。 CountDownLatch能够使一个线程在等待另外一些线程...

少年已不再年少
45分钟前
1
0
centos7 新手阿里云服务器安装mongodb

简介 MongoDB 是一个基于分布式 文件存储的NoSQL数据库 由C++语言编写,运行稳定,性能高 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 MongoDB特点 模式自由 :可以把不同结构的文档存...

醉雨
55分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部