muduo网络库源码学习————无界队列和有界队列
muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型。(这里以无界队列为例,有界队列和无界的差不多)代码如下:
BlockingQueue.h
#include <muduo/base/Condition.h>
#include <muduo/base/Mutex.h>
#include <boost/noncopyable.hpp>
#include <deque>
#include <assert.h>
namespace muduo
{
template<typename T>//队列模板
class BlockingQueue : boost::noncopyable
{
public:
BlockingQueue(): mutex_(), notEmpty_(mutex_),queue_()
{//构造函数对3个成员进行初始化
}
void put(const T& x)//生产产品
{
MutexLockGuard lock(mutex_);//先加上锁对队列进行保护,构造函数中调用lock,析构函数会自动调用unlock
queue_.push_back(x);//产品放进队列
//队列不为空,通知消费者可以进行消费
notEmpty_.notify(); // TODO: move outside of lock
}
T take()//消费产品
{
MutexLockGuard lock(mutex_);//加锁保护队列
// always use a while-loop, due to spurious wakeup
while (queue_.empty())//如果队列为空,则一直等待
{
notEmpty_.wait();
}
assert(!queue_.empty());//断言队列非空
T front(queue_.front());//取出队首元素
queue_.pop_front();//将队首元素弹出
return front;//返回队首元素
}
size_t size() const//队列大小
{
MutexLockGuard lock(mutex_);//加锁保护
return queue_.size();//返回队列大小
}
private:
mutable MutexLock mutex_;//互斥锁
Condition notEmpty_;//条件变量
std::deque<T> queue_;//队列使用stl中的deque
};
}
#endif // MUDUO_BASE_BLOCKINGQUEUE_H
测试代码有两个:
BlockingQueue_test.cc
#include <muduo/base/BlockingQueue.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Thread.h>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <string>
#include <stdio.h>
class Test
{
public://numThreads初始化为5,条件变量count初始化为5,线程个数也为5
Test(int numThreads) : latch_(numThreads), threads_(numThreads)
{
for (int i = 0; i < numThreads; ++i)
{//线程名称
char name[32];
snprintf(name, sizeof name, "work thread %d", i);
//创建5个线程,threadFunc为线程回调函数
threads_.push_back(new muduo::Thread(boost::bind(&Test::threadFunc, this), muduo::string(name)));
}
//启动线程
for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::start, _1));
}
void run(int times)
{
printf("waiting for count down latch\n");
latch_.wait();//等待count被减为0
printf("all threads started\n");
for (int i = 0; i < times; ++i)//100次
{
char buf[32];
snprintf(buf, sizeof buf, "hello %d", i);
queue_.put(buf);//往队列中添加100个产品
//打印信息
printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size());
}
}
void joinAll()
{
for (size_t i = 0; i < threads_.size(); ++i)
{//往5个线程添加stop
queue_.put("stop");
}
//执行join
for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::join, _1));
}
private:
//线程回调函数
void threadFunc()
{//输出线程id和名称
printf("tid=%d, %s started\n", muduo::CurrentThread::tid(),muduo::CurrentThread::name());
//计数值减一
latch_.countDown();//count减为0时将通知所有等待线程
bool running = true;
while (running)
{
std::string d(queue_.take());//消费产品
//打印取出的值
printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size());
//直到产品的名称==stop,跳出循环
running = (d != "stop");
}
//打印停止信息
printf("tid=%d, %s stopped\n",muduo::CurrentThread::tid(),muduo::CurrentThread::name());
}
muduo::BlockingQueue<std::string> queue_;//队列
muduo::CountDownLatch latch_;//条件变量
boost::ptr_vector<muduo::Thread> threads_;//线程数组
};
int main()
{//打印进程,线程id
printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid());
Test t(5);//定义test类
t.run(100);
t.joinAll();
printf("number of created threads %d\n", muduo::Thread::numCreated());
}
单独编译后运行结果如下:
BlockingQueue_bench.cc
#include <muduo/base/BlockingQueue.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <map>
#include <string>
#include <stdio.h>
class Bench//Bench是用来度量时间的一个类
{
public://count初始化为numThreads,创建numThreads个线程
Bench(int numThreads) : latch_(numThreads),threads_(numThreads)
{
for (int i = 0; i < numThreads; ++i)
{
char name[32];
snprintf(name, sizeof name, "work thread %d", i);
//创建线程,设置回调
threads_.push_back(new muduo::Thread( boost::bind(&Bench::threadFunc, this), muduo::string(name)));
}
//线程start
for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::start, _1));
}
void run(int times)//生产产品
{//10000个
printf("waiting for count down latch\n");
latch_.wait();//等待count降为0
printf("all threads started\n");
for (int i = 0; i < times; ++i)
{
muduo::Timestamp now(muduo::Timestamp::now());
queue_.put(now);//当前时间戳进队
usleep(1000);//1000微秒一次
}
}
void joinAll()
{
for (size_t i = 0; i < threads_.size(); ++i)
{
queue_.put(muduo::Timestamp::invalid());//产生非法时间,即产生跳出循环的条件
}
for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::join, _1));
}
private:
void threadFunc()//用于消费产品
{
printf("tid=%d, %s started\n",muduo::CurrentThread::tid(),muduo::CurrentThread::name());
//Map是STL[1] 的一个关联容器,它提供一对一
//(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力
//第一个是delay值,第二个是相同delay的次数
std::map<int, int> delays;//map容器
latch_.countDown();
bool running = true;
while (running)
{
muduo::Timestamp t(queue_.take());//取出队列中的时间戳
muduo::Timestamp now(muduo::Timestamp::now());//建立当前时间戳对象
if (t.valid())//如果是一个合法的时间
{//计算差值
int delay = static_cast<int>(timeDifference(now, t) * 1000000);//以微秒为单位
// printf("tid=%d, latency = %d us\n", muduo::CurrentThread::tid(), delay);
++delays[delay];//??
}
running = t.valid();//t为非法的时间则跳出循环
}
printf("tid=%d, %s stopped\n", muduo::CurrentThread::tid(),muduo::CurrentThread::name());
//使用迭代器遍历map容器
for (std::map<int, int>::iterator it = delays.begin(); it != delays.end(); ++it)
{
printf("tid = %d, delay = %d, count = %d\n",muduo::CurrentThread::tid(),it->first, it->second);
}
}
muduo::BlockingQueue<muduo::Timestamp> queue_;
muduo::CountDownLatch latch_;
boost::ptr_vector<muduo::Thread> threads_;
};
int main(int argc, char* argv[])
{//若参数大于1则是传入的参数,否则设为1
int threads = argc > 1 ? atoi(argv[1]) : 1;
Bench t(threads);//建立Bench对象
t.run(10000);
t.joinAll();
}
单独编译后运行结构如下:(输出过长,时间也太长,截图时中断了程序)
muduo网络库源码学习————无界队列和有界队列的更多相关文章
- muduo网络库源码学习————Timestamp.cc
今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...
- muduo网络库源码学习————线程池实现
muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的.线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也 ...
- muduo网络库源码学习————线程类
muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...
- muduo网络库源码学习————互斥锁
muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁. ...
- muduo网络库源码学习————线程特定数据
muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...
- muduo网络库源码学习————日志滚动
muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...
- muduo网络库源码学习————日志类封装
muduo库里面的日志使方法如下 这里定义了一个宏 #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) ...
- muduo网络库源码学习————线程本地单例类封装
muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...
- muduo网络库源码学习————线程安全
线程安全使用单例模式,保证了每次只创建单个对象,代码如下: Singleton.h // Use of this source code is governed by a BSD-style lice ...
随机推荐
- Java第二十一天,集合三大接口Set、List、Map的新方法——of方法
of public static List<E> of(E.....e) 这是jdk 9推出的一个针对于Set,List,Map三大集合接口的新方法. 注意: 是静态方法. 只适用于Set ...
- javascript 入门 之 bootstrap/bootstrap-table 安装方法
也和select2一样,可以有三种方法 1.远程调用CDN 2.用bower安装 3.下载 时间原因,暂时先讲第二种,其余两种,以后完善 1.进入根目录,执行bower install bootstr ...
- 详解java访问修饰符
详解java访问修饰符 为了防止初学者看到因为专业的术语而感觉晦涩难懂,我接下来尽量用生动比喻的说法来解释!首先第一点,我们来讲讲什么叫修饰符!看看这个名称,想想他的意思.修饰符!修饰符!,就是用来修 ...
- 十年测试老鸟告诉你--自动化测试选JAVA还是选Python--写给还在迷茫中的朋友
一.前言 Python和Java哪个更适合做自动化测试?这是很多测试工程师从功能跨入自动化纠结的问题,今天测试老鸟来带大家详细分析一下!写给还在迷茫中的朋友! 首先可以确认的是提出这个问题的肯定是一个 ...
- POj3017 dp+单调队列优化
传送门 解题思路: 大力推公式:dp[i]=min(dp[k]+max(k+1,i)){k>=0&&k<i},max(j,i)记为max(a[h]){h>k& ...
- 广告行业中那些趣事系列9:一网打尽Youtube深度学习推荐系统
最新最全的文章请关注我的微信公众号:数据拾光者. 摘要:本篇主要分析Youtube深度学习推荐系统,借鉴模型框架以及工程中优秀的解决方案从而应用于实际项目.首先讲了下用户.广告主和抖音这一类视频平台三 ...
- AtomicInteger的并发处理
AtomicInteger的并发处理 博客分类: Effective Java JDK1.5之后的java.util.concurrent.atomic包里,多了一批原子处理类.主要用于在高并发环 ...
- Wpf之HandyControls与MaterialDesign混用之DataGrid
首先在App.Xaml引入相关资源 <Application.Resources> <ResourceDictionary> <ResourceDictionary.Me ...
- 【python实现卷积神经网络】全连接层实现
代码来源:https://github.com/eriklindernoren/ML-From-Scratch 卷积神经网络中卷积层Conv2D(带stride.padding)的具体实现:https ...
- Ant安装与配置
1. 到apache 官网去下载最新版本的ant,http://ant.apache.org/:下载后直接解压缩到电脑上,不需要安装: 2.环境变量配置: 2.1 ->计算机右键->属性- ...