封装的线程池

news2024/12/23 4:34:37

1.首先写一个队列来存,线程

queue.c

#ifndef QUEUE_H
#define QUEUE_H
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct Queue
{
    void **arr;
    int cap;
    int front;
    int rear;
} Queue;
//创建队列
Queue *create_queue(int cap);
//销毁队列
void destroy_queue(Queue *queue);
//入队
void push_queue(Queue *queue, void *arg);
//出队
void *pop_queue(Queue *queue);
//队空
bool empty_queue(Queue *queue);
//队满
bool full_queue(Queue *queue);
//队头
void *front_queue(Queue *queue);
//队尾
void *rear_queue(Queue *queue);

#endif//QUEUE_H

queue.c

#include "queue.h"
//创建队列
Queue *create_queue(int cap)
{
    Queue *queue = malloc(sizeof(Queue));
    //多开辟一一个空间
    queue->arr=malloc(cap*sizeof(void*)*cap+1);
    queue->cap=cap;
    queue->front=0;
    queue->rear=0;
    return queue;
}
//销毁队列
void destroy_queue(Queue *queue)
{
    free(queue->arr);
    free(queue);
}
//入队
void push_queue(Queue *queue, void *arg)
{
    //队尾入队
    queue->arr[queue->rear++]=arg;
    queue->rear%=queue->cap;

}
//出队
void *pop_queue(Queue *queue)
{
    queue->front=(queue->front+1)%queue->cap;
}
//队空
bool empty_queue(Queue *queue)
{
    return queue->front==queue->rear;
}

//队已满
bool full_queue(Queue *queue)
{
    return (queue->rear+1)%queue->cap==queue->front;
}
//队头
void *front_queue(Queue *queue)
{
    return queue->arr[queue->front];
}
//队尾
void *rear_queue(Queue *queue)
{
    return queue->arr[(queue->rear+queue->cap-1)%queue->cap];
}


2.利用队列,写一个线程池

thread_pool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "queue.h"
typedef void (*EnterFP)(void *);//线程真正的业务逻辑函数格式
typedef struct ThreadPool {
    int thread_cnt;//线程数量
    pthread_t *tids;//创建线程id
    Queue *store;//队列仓库
    EnterFP enter;//线程真正的业务逻辑函数
    pthread_mutex_t hlock;//队头互斥锁
    pthread_mutex_t tlock;//队尾互斥锁
    pthread_cond_t empty;//空仓库条件变量
    pthread_cond_t full;//满仓库条件变量

} ThreadPool;

//创建线程池
ThreadPool *create_threadpool(int thread_cnt,int store_cap, EnterFP enter);

//启动线程池
void start_threadpool(ThreadPool *threadpool);
//生成数据
void push_threadpool(ThreadPool *threadpool, void *task);
//消费数据
void *pop_threadpool(ThreadPool *threadpool);
//销毁线程池
void destroy_threadpool(ThreadPool *threadpool);



#endif//THREADPOOL_H

pthread_pool.c

#include<stdlib.h>
#include "threadpool.h"

//线程池的线程的入口函数
static void *run(void *arg)
{
    ThreadPool *threadpool=(ThreadPool*)arg;
    while(1)
    {
        //线程就负责消费数据,能返回就意味着从仓库里拿到了数据
        void *task=pop_threadpool(threadpool);
        //拿到数据,去运行线程要执行的业务逻辑函数
        threadpool->enter(task);//?
    }
}
//消费数据



//创建线程池
ThreadPool *create_threadpool(int thread_cnt,int store_cap, EnterFP enter)
{
    //申请线程池内存
    ThreadPool*threadpool=malloc(sizeof(ThreadPool));
    //申请线程内存
    threadpool->tids=malloc(sizeof(pthread_t)*thread_cnt);
    //创建仓库队列
    threadpool->store=create_queue(store_cap);
    //初始化线程容量
    threadpool->thread_cnt=thread_cnt;
    //初始化线程业务逻辑函数
    threadpool->enter=enter;
    //初始化互斥锁,条件变量
    pthread_mutex_init(&threadpool->hlock,NULL);
    pthread_mutex_init(&threadpool->tlock,NULL);
    pthread_cond_init(&threadpool->empty,NULL);
    pthread_cond_init(&threadpool->full,NULL);
    return threadpool;
}
//启动线程池
void start_threadpool(ThreadPool *threadpool)
{
    for(int i=0;i<threadpool->thread_cnt;i++)
    {
        //创建线程
        pthread_create(&threadpool->tids[i],NULL,run,threadpool);
    }
}
//生成数据
void push_threadpool(ThreadPool *threadpool, void *task)
{
    //队尾加锁
    pthread_mutex_lock(&threadpool->tlock);
    //如果队满,不生产
    while(full_queue(threadpool->store))
    {
        //唤醒消费者数据的线程
        pthread_cond_signal(&threadpool->empty);
        //睡眠并解锁队尾
        pthread_cond_wait(&threadpool->full,&threadpool->tlock);
    }
    //生产数据存入队尾
    push_queue(threadpool->store,task);
    //唤醒一个消费者数据的线程
    pthread_cond_signal(&threadpool->empty);
    //队尾解锁
    pthread_mutex_unlock(&threadpool->tlock);
}
//消费数据
void *pop_threadpool(ThreadPool *threadpool)
{
      //队头加锁
    pthread_mutex_lock(&threadpool->hlock);
    //如果一直队空,不消费
    while(empty_queue(threadpool->store))
    {
        //唤醒生产者数据的线程
        pthread_cond_signal(&threadpool->full);
        //睡眠并解锁队头
        pthread_cond_wait(&threadpool->empty,&threadpool->hlock);
    
    }
    //消费数据
    void *task=front_queue(threadpool->store);

    pop_queue(threadpool->store);
    //唤醒一个生产者者数据的线程
    pthread_cond_signal(&threadpool->full);
    //队头解锁
    pthread_mutex_unlock(&threadpool->hlock);

    return task;
}
//销毁线程池
void destroy_threadpool(ThreadPool *threadpool)
{
    //结束线程池中所有的消费者线程
    for(int i=0;i<threadpool->thread_cnt;i++)
    {
        pthread_cancel(threadpool->tids[i]);
    }
    pthread_cond_destroy(&threadpool->empty);
    pthread_cond_destroy(&threadpool->full);
    pthread_mutex_destroy(&threadpool->hlock);
    pthread_mutex_destroy(&threadpool->tlock);
    destroy_queue(threadpool->store);
    free(threadpool->tids);
    free(threadpool);


}



3.线程池已经封装好了,先在来写服务器,和客户端来测试

    tcp_s.c:服务端

#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#include"threadpool.h"
//业务逻辑
void enter(void*arg)
{
    int cli_fd=*(int*)arg;
    char buf[4096];
    size_t buf_size=sizeof(buf);

    for(;;)
    {
        int ret=recv(cli_fd,buf,buf_size,0);
        if(ret<=0||0==strcmp(buf,"quit"))
        {
            //关闭套接字
           close(cli_fd);
           //释放资源
           free(arg);
           printf("客户端退出\n");
           return;
        }
        printf("recv:%s bits:%d \n",buf,ret);
        strcat(buf,"return");

        ret=send(cli_fd,buf,strlen(buf)+1,0);
        if(ret<=0)
        {
            close(cli_fd);
            free(arg);
            printf("客户端退出\n");
            return;
        }

    }
}




int main(int argc,char *argv[]) {

    int svr_fd=socket(AF_INET,SOCK_STREAM,0);
    if(svr_fd<0)
    {
    printf("socket error\n");
    return -1;
    }

    struct sockaddr_in addr={};
    addr.sin_family=AF_INET;
    //字符串转化为数字
    addr.sin_port=htons(atoi(argv[2]));
    addr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t addrlen=sizeof(addr);

    if(bind(svr_fd,(struct sockaddr*)&addr,addrlen))
    {
    printf("bind error\n");
    return -1;
    }
    //监听
    if(listen(svr_fd,10))
    {
        perror("listen error");
        return -1;
    }
    
    ThreadPool*threadpool=create_threadpool(10,20,enter);
    start_threadpool(threadpool);
    while(1)
    {
        //主线程这边相当于生产者
        int *cli_fd_p=malloc(sizeof(int));
        *cli_fd_p=accept(svr_fd,(struct sockaddr*)&addr,&addrlen);
        push_threadpool(threadpool,cli_fd_p);
   
    }

    


}


tcp_c.c 客户端

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>

typedef struct sockaddr *SP;

int main(int argc,const char* argv[])
{
    //创建socket
    int cli_fd=socket(AF_INET,SOCK_STREAM,0);
    if(cli_fd<0)
    {
        perror("socket");
        return -1;
    }
    //准备通信地址
    struct sockaddr_in addr={};
    addr.sin_family=AF_INET;
    addr.sin_port=htons(8888);
    addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    socklen_t addrlen=sizeof(addr);
    //连接服务器
    if(connect(cli_fd,(SP)&addr,addrlen))
    {
        perror("connect");
        return -1;
    }

    char buf[4096];
    size_t buf_size=sizeof(buf);
    while(1)
    {
        //发送请求
        printf(">>>>>");
        scanf("%s",buf);
        int ret=send(cli_fd,buf,strlen(buf)+1,0);
        //ret=write(cli_fd,buf,strlen(buf)+1);
        if(ret<=0)
        {
            printf("服务器正在升级,请稍后重试\n");
            break;
        }
        if(0==strcmp("quit",buf))
        {
            printf("通信结束\n");
            break;
        }
        //接收请求
        //int ret=read(cli_fd,buf,buf_size);
        ret=recv(cli_fd,buf,buf_size,0);
        if(ret<=0)
        {
            printf("服务器正在维护,请稍候重试\n");
            break;
        }
        printf("read:%s bits:%d\n",buf,ret);
    }
        
    return 0;
}

4.下面看测试结果

我用了两个客户端

客户端1

客户端2

封装的线程成功!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2203052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手动nginx平滑升级

一、下载nginx安装包 wget http://nginx.org/download/nginx-1.24.0.tar.gz 二、解压缩 tar -zxf nginx-1.24.0.tar.gz 三、进入解压缩后文件 3.1 cd /usr/local/nginx/sbin 预编译 进入如下命令 ./configure -prefix/usr/local/nginx --with-http_ssl_module --with…

Rust 与生成式 AI:从语言选择到开发工具的演进

在现代软件开发领域&#xff0c;Rust 语言正在逐步崭露头角&#xff0c;尤其是在高性能和可靠性要求较高的应用场景。与此同时&#xff0c;生成式 AI 的崛起正在重新塑造开发者的工作方式&#xff0c;从代码生成到智能调试&#xff0c;生成式 AI 的应用正成为提升开发效率和质量…

Linux操作系统小项目——实现《进程池》

文章目录 前言&#xff1a;代码实现&#xff1a;原理讲解&#xff1a;细节处理&#xff1a; 前言&#xff1a; 在前面的学习中&#xff0c;我们简单的了解了下进程之间的通信方式&#xff0c;目前我们只能知道父子进程的通信是通过匿名管道的方式进行通信的&#xff0c;这是因…

Linux权限和软件包

前言 今天我们简单的介绍Linux中的两个概念&#xff0c;分别是权限和软件包。Linux中一切皆文件&#xff0c;权限无非就是限制不同的角色对文件的能不能得问题&#xff0c;软件包则是简单介绍一下Linux中安装卸载程序 权限 权限针对的对象是角色&#xff0c;首先我们先来介绍…

阿里云dataworks测试

文章目录 开始查看全局信息查看数据源信息(endpoint与project的信息)查看绑定、解绑钉钉创建、查看AccessKey(Access Key ID与Access Key Secret) 线上开发新建开发节点mysqlpython 本地开发python 程序调度 开始 参考文档&#xff1a;https://help.aliyun.com/zh/ram/user-gu…

新建的SpringBoot项目结构为空的可能问题与解决方案

问题&#xff1a; 如下图&#xff0c;创建一个名为springboot_demo05的SpringBoot项目的时候&#xff0c;发现创建的项目结构为空&#xff0c;没有下一级目录。但是在新窗口新建一个项目的时候没有这个问题。 打开Maven工具发现也没有关联Maven依赖模型 原因排查&#xff1a; …

abc371 f

F - Takahashi in Narrow Road 我们可以发现&#xff0c;每次操作后&#xff0c;对于一段变化后的区间&#xff0c;其变为了一段公差为1的等差数列&#xff0c;所以我们如果把每个值减去对应的下标&#xff0c;那么对应的区间变化后&#xff0c;都为一个相同的值&#xff0c;这…

观诺奖感言:学好数理化,都被AI打趴下!

10月8日&#xff0c;瑞典皇家科学院宣布&#xff0c;将2024年诺贝尔物理学奖授予两位人工智能先驱——约翰霍普菲尔德&#xff08;John Hopfield&#xff09;和杰弗里辛顿&#xff08;Geoffrey Hinton&#xff09;。 在接到瑞典方打来的电话后&#xff0c;Hinton还在反复确认&a…

ssm基于Javaee的影视创作论坛的设计与实现

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 III 第1章 绪论 1 1.1选题动因 1 1.2目的和意义 1 1.3论文结构安排 2 第2章 开发环境与技术 …

刷题 双指针 滑动窗口

面试经典 150 题 - 双指针 125. 验证回文串⭐️ 学会内部字母处理函数的使用 class Solution { public:bool isPalindrome(string s) {int left 0, right s.size() - 1;while (left < right) {// 处理左边字符if (!isalnum(s[left])) {left;continue;}// 处理右边字符if…

2024 kali虚拟机安装教程,分两大步骤,图文讲解(1)

第二步链接&#xff1a; 2024 kali虚拟机安装教程&#xff0c;分两大步骤&#xff0c;图文讲解&#xff08;2&#xff09;-CSDN博客 准备工作 1.kali的iso镜像文件 2.VMware Workstation Pro 虚拟机软件 正式开始 1.创建新的虚拟机&#xff0c;勾选自定义&#xff08;高级…

King3399(ubuntu文件系统)风扇驱动

该文章仅供参考&#xff0c;编写人不对任何实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍King3399&#xff08;ubuntu文件系统&#xff09;风扇控制&#xff08;GPIO&#xff09;&#xff0c;涉及king-rk3399.dts设备树修改&#x…

职场人情世故,你一定要学

职场上工作固然是第一位&#xff0c;但看似平淡的人际关系的经营&#xff0c;是对工作的顺利展开有重要的辅助作用&#xff0c;人来人往&#xff0c;这几条处事你必须要懂&#xff0c;否则职场上升职、加薪会吃亏。 1、 看破不拆穿。 职场上你要活的很通透的人&#xff0c;对什…

从 Reno TCP 到 Scalable TCP,HighSpeed TCP

前文 Scalable TCP 如何优化长肥管道 介绍了 Scalable TCP&#xff0c;但联系另一个类似的算法 HighSpeed TCP(简称 HSTCP)&#xff0c;就会看到一个类似从 Reno TCP 经 BIC 到 CUBIC 的路线&#xff0c;但采用了不同的策略。 Reno TCP 经 BIC 到 CUBIC 路线的核心在于 “在长…

2024年最新(AI绘画)Stable Diffusion4.9下载及安装教程.

软件介绍 Stable Diffusion 是一款在图像生成领域具有重大影响力的软件。 从工作原理上看&#xff0c;它利用深度学习的先进算法&#xff0c;构建起复杂且强大的神经网络架构。其核心在于能够解读用户输入的文本信息&#xff0c;并将这些信息转化为图像的特征与细节。 在使用…

游戏出海:跨境卖家入驻G2A详细操作指南

《黑悟空神话》在海外爆火&#xff0c;游戏出海也成为了众多游戏开发商的热门选择。在这个趋势之下&#xff0c;G2A&#xff0c;这个专注于游戏出海的电商平台&#xff0c;凭借庞大的用户群体&#xff0c;为游戏卖家提供了一个触达全球玩家的绝佳平台。 对于想要拓展海外市场的…

【HTML】制作一个简易图片轮播器

1. 轮播器效果图 1. 正常状态下每 1.5秒 自动轮播下张图片&#xff0c;轮播结束从头开始重复 2. 鼠标悬停时停止轮播&#xff0c;可以选择左右图片切换 2. HTML 结构 文档类型声明&#xff1a;<!DOCTYPE html> 声明文档类型为HTML5。HTML标签&#xff1a;<html lang…

2024 闽盾杯-黑盾赛道WP

CRYPTO 签到题-学会SM https://www.json.cn/encrypt/sm3 题目要求小写所以需要转换一下 或者脚本&#xff1a; import hashlib message "heidun2024" hash_object hashlib.new(sm3) hash_object.update(message.encode(utf-8)) hash_value hash_object.hexdigest(…

【STM32单片机_(HAL库)】4-5-3【定时器TIM】【感应开关盖垃圾桶项目】项目实现

1.项目需求 以下几个事件触发时&#xff0c;垃圾桶自动开盖&#xff0c;并伴随蜂鸣器短响一声&#xff0c;同时 LED 灯闪烁一下&#xff0c;2秒后自动关盖&#xff1a; 检测到有人靠近检测到有震动按下按键 KEY1 2.硬件 STM32单片机最小系统震动传感器模块蜂鸣器模块&#…

对象比较工具类:实现对业务的修改记录保存(对象字段差异对比)

测试 1&#xff1a;User类 Data NoArgsConstructor AllArgsConstructor public class User {FieldLabel("姓名")private String name;FieldLabel("年龄")private Integer age;FieldLabel("手机")private String phone;FieldLabel("手机号…