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线程任务队列相关推荐

  1. 阻塞io阻塞io_Redis:RESP协议,阻塞IO 与非阻塞IO,Redis的线程模型

    1.Redis 阻塞IO 与非阻塞IO Java在JDK1.4 中引入了NIO ,但是也有很多人在使用阻塞IO,这两种IO有什么区别? 在阻塞模式下,如果你从数据流读取不到指定大小的数据量,IO就会阻 ...

  2. redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?...

    这个是问 redis 的时候,最基本的问题吧,redis 最基本的一个内部原理和特点,就是 redis 实际上是个单线程工作模型, 你要是这个都不知道,那后面玩儿 redis 的时候,出了问题岂不是什 ...

  3. redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    redis 的线程模型 redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型.它采用 IO 多路复用机制同时监听 ...

  4. 缓存数据库面试 - redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    缓存数据库面试 - redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis ...

  5. 【重难点】【Redis 01】为什么使用 Redis、Redis 的线程模型、Redis 的数据类型及其底层数据结构

    [重难点][Redis 01]为什么使用 Redis.Redis 的线程模型.Redis 的数据类型及其底层数据结构 文章目录 [重难点][Redis 01]为什么使用 Redis.Redis 的线程 ...

  6. 阿里蚂蚁金服中间件(Java 4轮面试题含答案):Redis缓存+线程锁+微服务等

    第一轮 说说HaspMap底层原理?再说说它跟HaspTable和ConcurrentHashMap他们之间的相同点和不同点? 讲讲jdk1.7和1.8的区别? 几种内置的线程池 MySQL事务隔离级 ...

  7. 后端开发【一大波有用知识】Redis的线程模型和异步机制

    文章目录 Redis 6.0引入多线程 异步机制 Redis pipeline技术 Redis 事务 ACID特性分析 redis 发布订阅 我们通常说,Redis 是单线程,主要是指 Redis 的 ...

  8. 简谈Redis的线程模型

    Redis线程模型 Redis真的是单线程的吗 ? 为什么说Redis单线程速度这么快? IO多路复用 Redis真的是单线程的吗 ? Redis的单线程主要是指处理网络IO请求和键值对的读写是单线程 ...

  9. Redis的线程模型

    Redis它是一个单线程的,这一点需要去注意的. 首先我们呢会有一个客户端,这个客户端在我们之前其实使用的是一个redis client 这样的一个工具去连接的redis server. 如果说我们后 ...

最新文章

  1. Intellij IDEA中使用Protobuf的正确姿势
  2. 关于sendinput() inserted only 0 out of 2 python程序问题的解决
  3. rp软件app流程图_Axure RP 9 for Mac交互原型设计软件
  4. Flink运行出现Assigned key must not be null
  5. JavaScript入门(part12)--内置对象
  6. 深度解析LSTM神经网络的设计原理
  7. 信息学奥赛C++语言: 求小数的某一位
  8. 来自 PHP 之外的变量(HTML 表单中的数组、变量名中的点)
  9. oracle数据库如何写翻页_ORACLE翻页SQL语句
  10. LoadRunner正确的登录压力测试方法实战
  11. 被称为“Google 最大黑科技”,开发谷歌大脑,这位 AI 掌门人到底有多牛?
  12. axios爬坑之provisional headers are shown
  13. python输入一个整数和一个字符_【python零基础入门】基础语法之变量、字符串、数字、规则。...
  14. 如何批量查询快递的签收状态?
  15. 新电脑小喇叭一直是红❌的解决方法
  16. 如何用Vue开发前端和网站
  17. Linux命令06 - - wget 下载网络文件
  18. 禅意花园网页设计_CSS教程:15.1 “禅意花园”页面HTML结构分析
  19. wince 百度地图懒人包_【分享】路虎高德V6.0+V33图资懒人包(WIN CE)【亲测】
  20. The file contains top level spacers. They will not be saved.Perhaps you forgot to create a layout

热门文章

  1. 新手与大佬学习方式的差异
  2. Mybatis01(结果集封装)
  3. JS格式化时间之后少了8个小时
  4. oracle 列 连续,sql 查寻某列连续的几个值是否相同
  5. c++——抽象类以及string知识点补充
  6. 职工考勤管理信息系统数据库课设_职工考勤管理信息系统数据库课程设计
  7. ThreadLocal原理和用法
  8. oracle within的用法,Oracle的 listagg() WITHIN GROUP ()函数使用
  9. Prometheus-使用Prometheus监控Kubernetes集群
  10. Mysql 获取年级每个班前十学生的信息