波奇学Linux:信号量环形队列,原生线程池,封装线程

基于信号量的多生产多消费环形队列

代码

cpp 复制代码
const static int defaultcap=5;

template<class T>
class RingQueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem); //资源-1
    }
    void V(sem_t &sem)
    {
        sem_post(&sem); //资源加一
    }
    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void Unlock(pthread_mutex_ &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int cap=defaultcap)
    :ringqueue_(cap),cap_(cap),c_step_(0),p_step_(0)
    {
        sem_init(&cdata_sem_,0,0); //初始化信号量
        sem_init(&pspace_sem_,0,cap_); //初始化信号量
        pthread_mutex_init(&c_mutex_,nullptr);
        pthread_mutex_init(&c_mutex_,nullptr);
    }
    void Push(const T&in) //生产
    {
        //先申请信号量后申请锁
        //能让两个申请并行,提高并发度
        //申请信号量是原子的
        P(pspace_sem_); 
        Lock(p_mutex_);
        ringqueue_[p_step_]=in;
         // 位置后移,维持环形特征
        p_step_++;
        p_step_%=cap_;
        
        Unlock(p_mutex_);
        V(cdata_sem_);
    }
    void Pop(T* out) //消费
    {
        P(cdata_sem_);
        Lock(c_mutex_);
        *out=ringqueue_[c_step_];
         // 位置后移动
        c_step_++;
        c_step_%=cap_;
        Unlock(c_mutex_);
        V(pspace_sem_);
    
    }
    ~RingQueue()
    {
        sem_destroy(&cdata_sem_); //释放信号量资源
        sem_destroy(&pspace_sem_);
        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }
private:
    std::vector<T> ringqueue_;
    int cap_;

    int c_step_; //消费者下标
    int p_step_; // 生产者下标
    // 使用信号量可以自动维护互斥性
    sem_t cdata_sem_; //消费者关注的数据资源
    sem_t pspace_sem_; // 生产者关注的空间资源

    pthread_mutex_t c_mutex_; // 多个生产者竞争对信号量的申请
    pthread_mutex_t p_mutex_; // 多个消费者竞争对信号量的申请
};

信号量保证生产者和消费者的同步关系

多线程就要上锁

问题思考

当多线程访问时如何,锁和信号量谁在前?

信号量申请在前,原因可以使得申请信号量和申请锁行为同步,申请信号量是原子的

当多个线程持有信号量时,会不会对消费资源进行误导?

不会,因为资源的消费取决于cdata_sem_,而当释放c_data_sem此时的确实已经表明资源量加1

当不会出现队列只剩下一个空位,但是有多个线程持有信号量?

不会,因为信号量和空位一一对应的,如果能申请到信号量说明确实有空位

线程池

接收任务,线程池里面的多个线程分配任务

代码

cpp 复制代码
#pragma once

#include<iostream>
#include<pthread.h>
#include<vector>
#include<queue>
#include<string>
#include<unistd.h>

struct ThreadInfo
{
    pthread_t tid;
    std::string name;
};
static const int defaultnum=5;

template<class T>
class ThreadPool
{
private:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wakeup() //唤醒进程
    {
        pthread_cond_signal(&cond_);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&cond_,&mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }
public:
    ThreadPool(int num=defaultnum)
    :threads_(num)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }
    //HandlerTask放在类里面会多出一个指针,要加上static
    static void* HandlerTask(void*args)
    {
        ThreadPool<T>*tp=static_cast<ThreadPool<T>*>(args);
        while(true)
        {
            tp->Lock();
            while(tp->IsQueueEmpty())
            {
                tp->ThreadSleep();
            }
            // T t=tp->Pop();
            
            tp->Unlock();
            // t(); //处理任务的同时不涉及共享资源,可以并发指行
        }
    }
    //初始化,创建多个线程
    void Start()
    {
        int num=threads_.size();
        for(int i=0;i<num;i++)
        {
            threads_[i].name="thread-"+std::to_string(i+1);
            pthread_create(&(threads_[i].tid),nullptr,HandlerTask,this);
        }
    }

    void Push(const T&t)
    {
        Lock();
        tasks_.push(t);
        Wakeup();
        Unlock();
    }
    T Pop()
    {
        T t=tasks_.front();
        tasks_.pop();
        return t;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
private:
    std::vector<ThreadInfo> threads_;
    std::queue<T> tasks_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

};

问题思考

在类里面调用HandlerTask函数

封装线程

代码

cpp 复制代码
#pragma once
#include<iostream>
#include<string>
#include<ctime>
#include<pthread.h>
typedef void (*callback_t)();
static int num=1;
class Thread
{
public:
    static void *Routine(void*args)
    {
        Thread* thread=static_cast<Thread*>(args);
        thread->Entery();
        return nullptr;
    }
public:
    Thread(callback_t cb)
    :tid_(0)
    ,name_("")
    ,start_timestamp_(0)
    ,isrunning_(false)
    ,cb_(cb)
    {

    }
    void Run()
    {
        name_="thread-" + std::to_string(num++);
        start_timestamp_=time(nullptr);
        isrunning_=true;
        pthread_create(&tid_,nullptr,Routine,this);
    }
    void Join()
    {
        pthread_join(tid_,nullptr);
        isrunning_=false;
    }
    std::string Name();
    uint64_t StartTimestamp();
    bool IsRunning()
    {
        return isrunning_;

    }
    void Entery()
    {
        cb_();
    }
    ~Thread()
    {

    }
private:
    pthread_t tid_; //线程tid
    std::string name_; //线程名字
    uint64_t start_timestamp_; //线程启动时间
    bool isrunning_; // 线程是否运行
    callback_t cb_; //回调函数
};
相关推荐
林开落L3 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
Prejudices15 分钟前
C++如何调用Python脚本
开发语言·c++·python
单音GG18 分钟前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
qing_04060335 分钟前
C++——多态
开发语言·c++·多态
孙同学_35 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
shitian08111 小时前
用轻量云服务器搭建一个开源的商城系统,含小程序和pc端
服务器·小程序·开源
charlie1145141911 小时前
Qt Event事件系统小探2
c++·qt·拖放·事件系统
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++
小辛学西嘎嘎1 小时前
C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
c语言·开发语言·c++
Biomamba生信基地1 小时前
Linux也有百度云喔~
linux·运维·服务器·百度云