【03.多线程】

线程

线程是进程中真正执行任务的基本单位
一个进程由多个称为线程的执行单元组成
同一进程的多个线程共享同样的代码和全局数据,共享整个虚拟地址空间,栈区通常是不共享的

线程同步

当多个线程共享相同内存时,需要确保每个线程看到一致的数据视图
如果每个线程使用的变量,其他线程都不会读取和修改
或变量只是只读的,那么就不会出现一致性问题
但当一个进程可以修改变量且其他线程也可以读取或修改,就需要线程同步,使用锁,可以保证同一时间只允许一个线程访问该变量
如果操作是原子操作,也就是操作只需要一个存储器周期,那么就不存在竞争,也就不需要同步

线程池

动态创建线程比较耗费时间,将导致较慢的响应
线程池是服务器预先创建好的一组线程,当有请求到来时,主线程选择线程池的某一个线程来为之服务,这样可以提高效率
通常的作法是所有线程通过一个共享的工作队列来同步,当工作队列为空时,工作线程都阻塞在该工作队列上。当有新的任务时,主线程将任务添加进工作队列,唤醒工作线程,某个工作线程处理任务,其他工作线程将继续等待。

代码

threadpool.h

#pragma once
#include <pthread.h>
#include <functional>
#include <deque>
class Threadpool
{
    typedef std::function<void()> Task;
public:
    static void* threadfunc(void* threadData);//线程运行函数
    Threadpool(int threadnum=4);
    ~Threadpool();
    void addtask(const Task &task);//任务入队
    int size();//任务队列长度
    Task poll();//弹出任务
private:
    pthread_t *threads_;
    int threadnum_;
    bool isrun_;//池子是否处于活动状态,当调用析构函数时置为false
    std::deque<Task> taskqueue_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
};

threadpool.cpp

#include "threadpool.h"
#include <stdio.h>
#include <assert.h>

void *Threadpool::threadfunc(void *threadData)
{
    pthread_t tid=pthread_self();
    Threadpool* pool=static_cast<Threadpool*>(threadData);
    while(pool->isrun_){
        Threadpool::Task task=pool->poll();
        if(!task){
            printf("thread %lu will exit\n",tid);
            break;
        }
        assert(task);
        task();
    }
    return nullptr;
}

Threadpool::Threadpool(int threadnum) : threadnum_(threadnum), isrun_(true)
{
    pthread_mutex_init(&mutex_,NULL);
    pthread_cond_init(&cond_,NULL);
    threads_=new pthread_t[threadnum_];
    for(int i=0;i<threadnum_;i++){
        pthread_create(&threads_[i],NULL,threadfunc,this);//创建线程
    }
}

Threadpool::~Threadpool()
{
    if(!isrun_)
        return;
    isrun_=false;
    pthread_cond_broadcast(&cond_);//唤醒所有工作线程
    for(int i=0;i<threadnum_;i++){
        pthread_join(threads_[i],NULL);//等待工作线程退出,回收资源
    }
    delete []threads_;
    threads_=nullptr;
    pthread_mutex_destroy(&mutex_);
    pthread_cond_destroy(&cond_);
}

void Threadpool::addtask(const Task &task)
{
    pthread_mutex_lock(&mutex_);
    taskqueue_.push_back(task);
    pthread_mutex_unlock(&mutex_);
    pthread_cond_signal(&cond_);//任务入队后唤醒工作线程,注意不一定只唤醒一个
}

int Threadpool::size()
{
    pthread_mutex_lock(&mutex_);
    int size=taskqueue_.size();
    pthread_mutex_unlock(&mutex_);
    return size;
}

Threadpool::Task Threadpool::poll()
{
    Task task=NULL;
    pthread_mutex_lock(&mutex_);
    while(taskqueue_.empty()&&isrun_)
        pthread_cond_wait(&cond_,&mutex_);//任务队列空且活动状态,阻塞工作线程
    if(!isrun_){//非活动状态直接返回
        pthread_mutex_unlock(&mutex_);
        return task;
    }
    assert(!taskqueue_.empty());
    task=taskqueue_.front();
    taskqueue_.pop_front();
    pthread_mutex_unlock(&mutex_);
    return task;
}

main.cpp

#include <iostream>
#include <string>
#include <unistd.h>
#include "threadpool.h"

using namespace std;

void print(std::string str){
    std::cout<<str<<std::endl;
}
void test()
{
    std::cout<<"hi"<<std::endl;
}

int main(){
    Threadpool *pool=new Threadpool();
    std::function<void()> func=std::bind(print,"hello world");
    pool->addtask(func);
    func=test;
    pool->addtask(func);
    sleep(1);//保证工作线程运行完整,主线程不会提前结束
    delete pool;
    return 0;
}

结果
在这里插入图片描述

参考
UNIX网络编程 卷1:套接字联网API 第3版
Linux高性能服务器编程——游双

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值