Linux多线程(线程池与单例模式)

embedded/2024/11/20 8:55:03/

目录

一、内存池

二、线程池的实现

1.线程池

2.任务文件

3.主函数

三、单例模式

1.懒汉模式

2.饿汉模式

3.线程安全


一、内存池

当用户调用new等函数的时候,会向内核申请空间。每调用一次申请一次空间而且空间不够时还会执行内存算法等,需要花费时间。因此在程序创建之初,OS索性直接将一大块内存分配给用户。

内存池的目的是为了提高效率,线程池也同理。

因此我们可以类比处线程池的概念,即提前创建一批线程,以便于随时处理任务。

二、线程池的实现

一个线程池除了包含大量线程之外,还包含一个任务队列。有一个生产任务的线程将任务传入任务队列中,线程池中的线程从任务队列中拿到任务,并进行处理。

1.任务文件

#include<iostream>
using namespace std;
namespace ns_task
{class Task{private:int x_;int y_;char op_;public:Task(int x,int y,char op):x_(x),y_(y),op_(op){};Task(){};int Run(){int res=0;switch(op_){case '+':res=x_+y_;break;case '-':res=x_-y_;break;case '*':res=x_*y_;break;case '/':res=x_/y_;break;case '%':res=x_%y_;break;default:cout<<"bug"<<endl;break;}cout<<"当前任务正在被"<<pthread_self()<<"处理"<<x_<<op_<<y_<<"="<<res<<endl;}};
}

2.线程池

#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
#include"Task.hpp"
using namespace ns_task;
namespace ns_threadpool
{template<class T>class ThreadPool{private:int num_;queue<T> task_queue_;pthread_mutex_t mtx;pthread_cond_t cond;public:ThreadPool(int num=5):num_(num){pthread_mutex_init(&mtx,nullptr);pthread_cond_init(&cond,nullptr);}bool IsEmpty(){return task_queue_.empty();}void lock(){pthread_mutex_lock(&mtx);}void unlock(){pthread_mutex_unlock(&mtx);}void Wait(){pthread_cond_wait(&cond,&mtx);}void Wakeup(){pthread_cond_signal(&cond);}void PushTask(const T& in){lock();task_queue_.push(in);unlock();Wakeup();}void PopTask(T* out){*out=task_queue_.front();task_queue_.pop();}static void* Routine(void* args){pthread_detach(pthread_self());ThreadPool<T>* tp=(ThreadPool<T>*)args;while(true){tp->lock();if(tp->IsEmpty()){tp->Wait();}T t;tp->PopTask(&t);tp->unlock();t.Run();}}void InitThreadPool(){pthread_t tid;for(int i=0;i<num_;i++){pthread_create(&tid,nullptr,Routine,(void*)this);}}~ThreadPool(){pthread_mutex_destroy(&mtx);pthread_cond_destroy(&cond);}};
}

3.主函数

#include"thread_pool.hpp"
using namespace ns_threadpool;
int main()
{ThreadPool<Task>* tp=new ThreadPool<Task>();srand((long long)time(nullptr));tp->InitThreadPool();while(true){int x=rand()%20+1;int y=rand()%10+1;char arr[]="+-*/%";char op=arr[rand()%1+4];Task t(x,y,op);tp->PushTask(t);sleep(1);}
}

三、单例模式

单例模式即只让对象在内存中存在一份,即一个类之定义一个对象,对于线程池来说只有一个线程池就够了。因此线程池的定义可以使用单例模式

一般而言,需要采用单例模式的情景是:

1.语义上只需要一个对象。

2.该对象内部存在大量空间保存大量数据,若存在多份(或各种拷贝),内存中就存在冗余数据。

1.懒汉模式

template<class T>
class Singleton
{
private:Singleton() {}Singleton(const Singleton<T>& a)=delete;Singleton<T>& operator=(Singleton<T>& a)=delete;static Singleton<T>* inst;
public:static T* GetInstance(){if(inst==NULL){inst=new T();}return inst;}
};
template<class T>
Singleton<T>* Singleton<T>::inst=nullptr; 

懒汉式的做法是,当需要使用对象的时候再创建一个对象。

2.饿汉模式

template<class T>
class Singleton
{
ptivate:Singleton() {}Singleton(const Singleton& a)=delete;Singleton<T>& operator=(Singleton<T>& a)=delete;static Singleton data;
public:static Singleton<T>* GetInstance(){return &data;}
};
template <class T>
Singleton<T> Singleton<T>::data=0;

饿汉模式表现为,当创建这个类的时候,对象已经创建好了,可以随时使用。

3.线程安全

由于单例本身会再任何场景,任何环境下被调用。因此可能会导致GetInstance被重入而产生线程安全问题。

我们可以使用单例模式改写线程池的代码:

此时需要将构造函数设为私有,只能调用GetInstance来获得类。

首先我们需要定义一个静态的线程池变量以及静态的线程池方法,我们使用懒汉模式来实现。

当一个线程进入GetInstance函数时,要创建变量,但是被切走了,此时其他线程进入,就会导致线程安全的问题,因此需要进行加锁的操作。

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include "task.hpp"
using namespace lf_task;namespace lf_threadpool
{template <class T>class ThreadPool{private:ThreadPool(int num = 5): _num(num){pthread_mutex_init(&mtx, nullptr);pthread_cond_init(&cond, nullptr);}ThreadPool(const ThreadPool<T>& tp)=delete;ThreadPool<T>& operator=(ThreadPool<T>& tp)=delete;static ThreadPool<T>* ins;public:static ThreadPool<T>* get_instance(){static pthread_mutex_t Lock=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&Lock);if(ins==nullptr){ins=new ThreadPool<T>();ins->InitThreadPool();}pthread_mutex_unlock(&Lock);return ins;}bool IsEmpty(){return _task_queue.empty();}void lock(){pthread_mutex_lock(&mtx);}void unlock(){pthread_mutex_unlock(&mtx);}void Wait(){pthread_cond_wait(&cond, &mtx);}void Wakeup(){pthread_cond_signal(&cond);}void PushTask(const T &in){pthread_mutex_lock(&mtx);_task_queue.push(in);pthread_mutex_unlock(&mtx);pthread_cond_signal(&cond);}void PopTask(T *out){*out = _task_queue.front();_task_queue.pop();}static void *Rountine(void *args){pthread_detach(pthread_self());ThreadPool<T> *tp = (ThreadPool<T> *)args;while (true){tp->lock();while (tp->IsEmpty()){tp->Wait();}T t;tp->PopTask(&t);tp->unlock();t.Run();}}void InitThreadPool(){pthread_t tid;for (int i = 0; i < _num; i++){pthread_create(&tid, nullptr, Rountine, (void *)this);}}~ThreadPool(){pthread_mutex_destroy(&mtx);pthread_cond_destroy(&cond);}private:int _num;queue<T> _task_queue;pthread_mutex_t mtx;pthread_cond_t cond;};template<class T>ThreadPool<T>* ThreadPool<T>::ins=nullptr;
}

同时主函数调用静态方法创建线程池:

#include"thread_pool.hpp"
using namespace ns_threadpool;
int main()
{srand((long long)time(nullptr));while(true){int x=rand()%20+1;int y=rand()%10+1;char arr[]="+-*/%";char op=arr[rand()%5];Task t(x,y,op);ThreadPool<Task>::get_instance()->PushTask(t);sleep(1);}
}


http://www.ppmy.cn/embedded/139030.html

相关文章

24.11.13 机器学习 特征降维(主成份分析) KNN算法 交叉验证(K-Fold) 超参数搜索

导包小总结(不全面): from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.feature_extraction import DictVectorizer(字典数据集的划分) from sklearn.feature_extraction.text import CountVectorizer(特征提取…

企业软文推广如何巧妙借力优质媒体,让品牌在市场中脱颖而出?媒介盒子分享

相比起线下的推广营销&#xff0c;在互联网时代&#xff0c;网络推广营销更符合现在企业品牌的宣传思路。因为相比起传统的营销方式&#xff0c;通过网络实现的线上推广能更精准的实现人群定位&#xff0c;更高效的提高营销资源的使用率&#xff0c;而软文推广&#xff0c;作为…

独立资源池与共享资源池在云计算中各自的优势

在云计算领域&#xff0c;独立资源池和共享资源池是两种关键的资源管理策略&#xff0c;它们各自具有独特的优势&#xff0c;以适应不同的业务需求和场景。 独立资源池的优势 资源独占性&#xff1a;独立资源池为特定应用或用户提供专属的资源&#xff0c;这意味着资源不会被其…

基于SpringBoot的旅游网站(程序+数据库+报告)

基于SpringBoot的旅游网站&#xff0c;系统包含两种角色&#xff1a;管理员、用户,系统分为前台和后台两大模块&#xff0c;主要功能如下。 【前台】&#xff1a; - 首页&#xff1a;展示旅游网站的核心内容&#xff0c;包括推荐的旅游线路、最新的旅游资讯等。 - 旅游线路&am…

Python爬虫下载新闻,Flask展现新闻(2)

上篇讲了用Python从新闻网站上下载新闻&#xff0c;本篇讲用Flask展现新闻。关于Flask安装网上好多教程&#xff0c;不赘述。下面主要讲 HTML-Flask-数据 的关系。 简洁版 如图&#xff0c;页面简单&#xff0c;主要显示新闻标题。 分页&#xff0c;使用最简单的分页技术&…

汽车资讯新篇章:Spring Boot技术启航

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

【Qt 蓝牙服务器实现】

在 Qt 中实现一个蓝牙服务器可以使用 Qt Bluetooth 模块。下面是一个基本的蓝牙服务器示例,它能够接受来自客户端的连接。 首先,请确保你已经安装了 Qt Bluetooth 模块并在项目文件中包含了相关库。 1. 项目文件 (.pro) 配置 在项目文件中添加以下行,以确保包含 Qt Bluet…

selenium元素定位---元素点击交互异常解决方法

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、异常原因 在编写ui自动化时&#xff0c;执行报错元素无法点击&#xff1a;ElementClickInterceptedException 具体报错&#xff1a;selenium.common.exc…