redis bio线程任务队列
bio部分是redis中负责后台进行文件关闭,aof文件缓冲区同步到磁盘,清理对象三种任务的部分。
/* Background job opcodes */
#define BIO_CLOSE_FILE 0 /* Deferred close(2) syscall. */
#define BIO_AOF_FSYNC 1 /* Deferred AOF fsync. */
#define BIO_LAZY_FREE 2 /* Deferred objects freeing. */
#define BIO_NUM_OPS 3
其中0,1,2代表三种工作内容,3则为bio中管理的后台任务类型数量,也就是前三者的数量。
static pthread_t bio_threads[BIO_NUM_OPS];
static pthread_mutex_t bio_mutex[BIO_NUM_OPS];
static pthread_cond_t bio_newjob_cond[BIO_NUM_OPS];
static pthread_cond_t bio_step_cond[BIO_NUM_OPS];
static list *bio_jobs[BIO_NUM_OPS];
bio_threads为存放工作线程的数组,数组大小为后台任务类型数量。
bio_mutex对应工作线程所需要的锁。
bio_newjob_cond为当任务队列为空,工作线程等待时等待被唤醒的cond。
bio_step_cond则为其他线程等待某任务执行时,监听的cond以试图被唤醒。
biojobs则为任务队列,是链表,用来存放相应类型准备执行的任务。
for (j = 0; j < BIO_NUM_OPS; j++) {void *arg = (void*)(unsigned long) j;if (pthread_create(&thread,&attr,bioProcessBackgroundJobs,arg) != 0) {serverLog(LL_WARNING,"Fatal: Can't initialize Background Jobs.");exit(1);}bio_threads[j] = thread;}
在bio的初试化方法bioInit()方法中,会依次建立三个执行bioProcessBackgroudJobs()方法的工作线程,存放在bio_threads中。
void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3) {struct bio_job *job = zmalloc(sizeof(*job));job->time = time(NULL);job->arg1 = arg1;job->arg2 = arg2;job->arg3 = arg3;pthread_mutex_lock(&bio_mutex[type]);listAddNodeTail(bio_jobs[type],job);bio_pending[type]++;pthread_cond_signal(&bio_newjob_cond[type]);pthread_mutex_unlock(&bio_mutex[type]);
}
当需要执行相应类型的后台任务的时候,需要通过bioCreateBackgroudJob()方法,首先,申请一个bio_job的空间,设置相应参数,然后根据任务类型加锁,将任务加入至任务队列,增加统计对应任务类型执行数量bio_pending,接下来唤醒处于等待bio_newjob_cond执行新任务的工作线程,以便执行相应的任务,最后解锁。
可以看到工作线程的真正执行逻辑的地方,bioProcessBackgrounJobs()。
if (type >= BIO_NUM_OPS) {serverLog(LL_WARNING,"Warning: bio thread started with wrong type %lu",type);return NULL;}/* Make the thread killable at any time, so that bioKillThreads()* can work reliably. */pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
在其开始,如果类型为不支持的任务类型,会直接结束。并将该线程设置为可随时终止的线程。
while(1) {listNode *ln;/* The loop always starts with the lock hold. */if (listLength(bio_jobs[type]) == 0) {pthread_cond_wait(&bio_newjob_cond[type],&bio_mutex[type]);continue;}/* Pop the job from the queue. */ln = listFirst(bio_jobs[type]);job = ln->value;/* It is now possible to unlock the background system as we know have* a stand alone job structure to process.*/pthread_mutex_unlock(&bio_mutex[type]);/* Process the job accordingly to its type. */if (type == BIO_CLOSE_FILE) {close((long)job->arg1);} else if (type == BIO_AOF_FSYNC) {redis_fsync((long)job->arg1);} else if (type == BIO_LAZY_FREE) {/* What we free changes depending on what arguments are set:* arg1 -> free the object at pointer.* arg2 & arg3 -> free two dictionaries (a Redis DB).* only arg3 -> free the skiplist. */if (job->arg1)lazyfreeFreeObjectFromBioThread(job->arg1);else if (job->arg2 && job->arg3)lazyfreeFreeDatabaseFromBioThread(job->arg2,job->arg3);else if (job->arg3)lazyfreeFreeSlotsMapFromBioThread(job->arg3);} else {serverPanic("Wrong job type in bioProcessBackgroundJobs().");}zfree(job);/* Lock again before reiterating the loop, if there are no longer* jobs to process we'll block again in pthread_cond_wait(). */pthread_mutex_lock(&bio_mutex[type]);listDelNode(bio_jobs[type],ln);bio_pending[type]--;/* Unblock threads blocked on bioWaitStepOfType() if any. */pthread_cond_broadcast(&bio_step_cond[type]);}
接下来,就会进入循环,在循环开始,如果对应任务类型的任务队列为空,阻塞并准备被bio_newjob_cond唤醒。当上文的bioCreateBackgroudJob()方法被调用,证明任务队列中有新任务被增加,被唤醒后从新开始循环,在队伍列表中的头部获取任务,并根据对应的任务类型取得job中的参数执行。
在执行完毕之后释放job的空间,加锁并删除队列里的任务,对应统计任务数量的bio_pending减一,表示任务数量减一,并广播唤醒因为对应类型的bio_step_cond被阻塞的线程。
redis bio线程任务队列相关推荐
- 阻塞io阻塞io_Redis:RESP协议,阻塞IO 与非阻塞IO,Redis的线程模型
1.Redis 阻塞IO 与非阻塞IO Java在JDK1.4 中引入了NIO ,但是也有很多人在使用阻塞IO,这两种IO有什么区别? 在阻塞模式下,如果你从数据流读取不到指定大小的数据量,IO就会阻 ...
- redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?...
这个是问 redis 的时候,最基本的问题吧,redis 最基本的一个内部原理和特点,就是 redis 实际上是个单线程工作模型, 你要是这个都不知道,那后面玩儿 redis 的时候,出了问题岂不是什 ...
- redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
redis 的线程模型 redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型.它采用 IO 多路复用机制同时监听 ...
- 缓存数据库面试 - redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
缓存数据库面试 - redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis ...
- 【重难点】【Redis 01】为什么使用 Redis、Redis 的线程模型、Redis 的数据类型及其底层数据结构
[重难点][Redis 01]为什么使用 Redis.Redis 的线程模型.Redis 的数据类型及其底层数据结构 文章目录 [重难点][Redis 01]为什么使用 Redis.Redis 的线程 ...
- 阿里蚂蚁金服中间件(Java 4轮面试题含答案):Redis缓存+线程锁+微服务等
第一轮 说说HaspMap底层原理?再说说它跟HaspTable和ConcurrentHashMap他们之间的相同点和不同点? 讲讲jdk1.7和1.8的区别? 几种内置的线程池 MySQL事务隔离级 ...
- 后端开发【一大波有用知识】Redis的线程模型和异步机制
文章目录 Redis 6.0引入多线程 异步机制 Redis pipeline技术 Redis 事务 ACID特性分析 redis 发布订阅 我们通常说,Redis 是单线程,主要是指 Redis 的 ...
- 简谈Redis的线程模型
Redis线程模型 Redis真的是单线程的吗 ? 为什么说Redis单线程速度这么快? IO多路复用 Redis真的是单线程的吗 ? Redis的单线程主要是指处理网络IO请求和键值对的读写是单线程 ...
- Redis的线程模型
Redis它是一个单线程的,这一点需要去注意的. 首先我们呢会有一个客户端,这个客户端在我们之前其实使用的是一个redis client 这样的一个工具去连接的redis server. 如果说我们后 ...
最新文章
- Intellij IDEA中使用Protobuf的正确姿势
- 关于sendinput() inserted only 0 out of 2 python程序问题的解决
- rp软件app流程图_Axure RP 9 for Mac交互原型设计软件
- Flink运行出现Assigned key must not be null
- JavaScript入门(part12)--内置对象
- 深度解析LSTM神经网络的设计原理
- 信息学奥赛C++语言: 求小数的某一位
- 来自 PHP 之外的变量(HTML 表单中的数组、变量名中的点)
- oracle数据库如何写翻页_ORACLE翻页SQL语句
- LoadRunner正确的登录压力测试方法实战
- 被称为“Google 最大黑科技”,开发谷歌大脑,这位 AI 掌门人到底有多牛?
- axios爬坑之provisional headers are shown
- python输入一个整数和一个字符_【python零基础入门】基础语法之变量、字符串、数字、规则。...
- 如何批量查询快递的签收状态?
- 新电脑小喇叭一直是红❌的解决方法
- 如何用Vue开发前端和网站
- Linux命令06 - - wget 下载网络文件
- 禅意花园网页设计_CSS教程:15.1 “禅意花园”页面HTML结构分析
- wince 百度地图懒人包_【分享】路虎高德V6.0+V33图资懒人包(WIN CE)【亲测】
- The file contains top level spacers. They will not be saved.Perhaps you forgot to create a layout
热门文章
- 新手与大佬学习方式的差异
- Mybatis01(结果集封装)
- JS格式化时间之后少了8个小时
- oracle 列 连续,sql 查寻某列连续的几个值是否相同
- c++——抽象类以及string知识点补充
- 职工考勤管理信息系统数据库课设_职工考勤管理信息系统数据库课程设计
- ThreadLocal原理和用法
- oracle within的用法,Oracle的 listagg() WITHIN GROUP ()函数使用
- Prometheus-使用Prometheus监控Kubernetes集群
- Mysql 获取年级每个班前十学生的信息