当前位置: 首页 > news >正文

飞机多少钱一架/优化网站标题是什么意思

飞机多少钱一架,优化网站标题是什么意思,徐州建设局网新网站,webp 做网站文章目录前言思路实现前言 这段时间看了《C并发编程实战》的基础内容,想着利用最近学的知识自己实现一个简单的线程池。 思路 个人对线程池的理解是:利用已经创建的固定数量的线程去执行指定的任务,从而避免线程重复创建和销毁带来的额外开…

文章目录

  • 前言
  • 思路
  • 实现

前言

这段时间看了《C++并发编程实战》的基础内容,想着利用最近学的知识自己实现一个简单的线程池。

思路

个人对线程池的理解是:利用已经创建的固定数量的线程去执行指定的任务,从而避免线程重复创建和销毁带来的额外开销。
C++11中,线程我们可以理解为对应一个thread对象,任务可以理解为要执行的函数,通常是耗时的函数。
我们的任务多少和顺序并非固定的,因此需要有一个方法能添加指定的任务,任务存放的地方应该是一个任务队列,因为我们的线程数量有限,当任务很多时同时执行的任务数量也有限,因此任务需要排队,遵循先来后到的原则。
当要执行一个任务时,意味着先将这个任务从队列取出,再执行相应任务,而“取出”动作的执行者是线程池中的线程,这意味我们的队列需要考虑多个线程在同一队列上执行“取出”操作的问题,实际上,取出任务操作和添加任务操作也不能同时进行,否则会产生竞争条件;另一方面,程序本身如果就是多线程的,多个线程同时添加任务的操作也应该是互斥的。
当没有任务可以执行时,所有线程应该什么也不做,当出现了一个任务时,应该将这个任务分配到任一线程中执行。实现上我们固然可以使用轮询的方式判断当前队列是否有任务,有则取出(即使加了互斥锁似乎也无法避免竞争条件?),但这样会消耗无谓的CPU资源,写轮询周期难以选取。其实,我们可以使用condition_variable代替轮询。
上述任务的创建和取出其实就是经典的生产者消费者模型。
我们将上面的内容都封装在一个类中,取名ThreadPool,用户可以在构造ThreadPool对象时指定线程池大小,之后可以随时添加要执行的任务。

实现

class ThreadPool
{
public:ThreadPool(int n);~ThreadPool();void pushTask(packaged_task<void()> &&task);private:vector<thread*> threadPool;deque<packaged_task<void()>> taskQueue;void taskConsumer();mutex taskMutex;condition_variable taskQueueCond;
};ThreadPool::ThreadPool(int n)
{for (int i = 0; i < n; i++){thread *t = new thread(&ThreadPool::taskConsumer,this);threadPool.push_back(t);t->detach();}
}ThreadPool::~ThreadPool()
{while (!threadPool.empty()){thread *t=threadPool.back();threadPool.pop_back();delete t;}
}void ThreadPool::pushTask(packaged_task<void()> &&task)
{{lock_guard<mutex> guard(taskMutex);taskQueue.push_back(std::move(task));}taskQueueCond.notify_one();
}void ThreadPool::taskConsumer()
{while (true){unique_lock<mutex> lk(taskMutex);taskQueueCond.wait(lk, [&] {return !taskQueue.empty(); });packaged_task<void()> task=std::move(taskQueue.front());taskQueue.pop_front();lk.unlock();task();}
}

这里我使用packaged_task作为任务,每当添加一个任务,就调用condition_variable::notify_one方法,调用condition_variable::wait的线程就会被唤醒,并检查等待条件。这里有个小细节是notify_one在解锁后执行,这样避免线程唤醒后还要等待互斥锁解锁。
使用示例:

void Task1()
{Sleep(1000);cout << "Task1"<<endl;
}void Task5()
{Sleep(5000);cout << "Task5" << endl;
}class Worker
{
public:void run();
};void Worker::run()
{cout << "Worker::run start" << endl;Sleep(5000);cout << "Worker::run end" << endl;
}int main()
{ThreadPool pool(2);pool.pushTask(packaged_task<void()>(Task5));pool.pushTask(packaged_task<void()>(Task1));pool.pushTask(packaged_task<void()>(Task1));Worker worker;pool.pushTask(packaged_task<void()>(bind(&Worker::run,&worker)));pool.pushTask(packaged_task<void()>([&](){worker.run();}));Sleep(20000);
}

这个线程池目前有几个缺点:

  1. 只能传入调用形式为void()形式的函数或可调用对象,不能返回任务执行的值,只能通过其他方式同步任务执行结果(如果有)
  2. 传入参数较为复杂,必须封装一层packaged_task,调用对象方法时需要使用bind或者lambda表达式的方法封装

以上缺点在当前版本的实现不予解决,日后另写博文优化。
2021/12/29 更新之一
事实上,我们只要将packaged_task改为funtion模板类,就可以简化我们的调用参数:

class ThreadPool
{
public:ThreadPool(int n);~ThreadPool();void pushTask(function<void()> task);private:vector<thread*> threadPool;deque<function<void()>> taskQueue;void taskConsumer();mutex taskMutex;condition_variable taskQueueCond;
};ThreadPool::ThreadPool(int n)
{for (int i = 0; i < n; i++){thread *t = new thread(&ThreadPool::taskConsumer,this);threadPool.push_back(t);t->detach();}
}ThreadPool::~ThreadPool()
{while (!threadPool.empty()){thread *t=threadPool.back();threadPool.pop_back();delete t;}
}void ThreadPool::pushTask(function<void()> task)
{{lock_guard<mutex> guard(taskMutex);taskQueue.push_back(std::move(task));}taskQueueCond.notify_one();
}void ThreadPool::taskConsumer()
{while (true){unique_lock<mutex> lk(taskMutex);taskQueueCond.wait(lk, [&] {return !taskQueue.empty(); });function<void()> task=taskQueue.front();taskQueue.pop_front();lk.unlock();task();}
}

调用代码改为如下:

ThreadPool pool(2);
pool.pushTask(&Task5);
pool.pushTask(&Task1);
pool.pushTask(&Task1);
Worker worker;
pool.pushTask((bind(&Worker::run, &worker)));
pool.pushTask([&](){worker.run(); });//1
Sleep(15000);

我们可以执行指定的函数,也可以将要执行的代码放入lambda表达式的函数体中,正如1处所示,这样就能在其他线程中执行指定的代码了。
2021/12/29 更新之二
我们发现,main最后都要调用sleep函数来避免主线程在线程任务完成之前就退出,因此我们希望添加一个接口,等待线程所有任务完成,改进如下,其他函数同前:

class ThreadPool
{
public:ThreadPool(int n);~ThreadPool();void pushTask(function<void()> task);void waitAllTask();private:vector<thread*> threadPool;deque<function<void()>> taskQueue;atomic<int> busyCount;bool bStop;void taskConsumer();mutex taskQueueMutex;condition_variable taskQueueCond;condition_variable taskFinishedCond;
};void ThreadPool::taskConsumer()
{while (!bStop){unique_lock<mutex> lk(taskQueueMutex);taskQueueCond.wait(lk, [&] {return !taskQueue.empty(); });busyCount++;function<void()> task=taskQueue.front();taskQueue.pop_front();lk.unlock();task();busyCount--;taskFinishedCond.notify_one();}
}void ThreadPool::waitAllTask()
{unique_lock<mutex> lk(taskQueueMutex);taskFinishedCond.wait(lk, [&] {return taskQueue.empty() && busyCount==0; });//所有任务均已完成
}

这样我们只要调用waitAllTask就可以等待所有任务完成啦。

http://www.lbrq.cn/news/1438597.html

相关文章:

  • 江苏省建设工程一站式申报网站/360关键词排名推广
  • 上海市城乡建设与管理委员会网站/韩国日本比分
  • w网站建设/优化课程设置
  • 青岛建站合作/网站查询服务器
  • 中国社会科学院/石家庄百度快照优化排名
  • 如何针对你的网站做搜索优化/网站搜索优化官网
  • 什么是域名解析/网络优化推广公司哪家好
  • 个人动漫网站怎么做页面/信息流广告模板
  • 成都b2c网站/百度之家
  • 做跟单员的话应该关注哪些网站/东莞企业推广网站制作
  • 英文建站模板/网址怎么创建
  • php靓号网站源码/属于网络营销特点的是
  • 翻译国外网站做原创/免费b2b
  • 网页开发者工具怎么用/苏州seo报价
  • 做网站有用吗/百度网盘资源搜索引擎搜索
  • 运维网站制作/会计培训班初级费用
  • 线下推广活动/南昌网站seo外包服务
  • 两人做性视频网站/深圳seo博客
  • 如何建立自己的平台/惠州市seo广告优化营销工具
  • 高中男女做那个视频网站/bing收录提交
  • 织梦网站在css中怎样做导航栏/免费二级域名注册申请
  • 广东哪家网站建设网页设计服务/营销策略手段有哪些
  • 在建项目备案人员查询/南宁seo产品优化服务
  • 企业网站seo外包 s/国际新闻网
  • 网站制作工资/网络优化工程师前景
  • 深圳营销外贸网站制作/百度用户服务中心人工24小时电话
  • 网站 模板/高清视频线和音频线的接口类型
  • 花20亿做网站/淘宝关键词指数
  • 比较著名的网站用javaweb做的/百度新闻发布平台
  • 深圳华强北做网站/竞猜世界杯
  • 计算机如何进行“卷积”操作:从图像到矩阵的奥秘
  • 【Linux学习|黑马笔记|Day3】root用户、查看权限控制信息、chmod、chown、快捷键、软件安装、systemctl、软连接、日期与时区
  • Java 基础概念笔记
  • 锂电池自动化生产线:智能制造重塑能源产业格局
  • 黑盒测试:用户视角下的软件“体检”
  • PCBA:电子产品制造的核心环节