Redis真的是单线程吗

129 阅读3分钟

在 main 函数完成参数解析后,会根据两个配置参数 daemonize 和 supervised,来设置变量 background 的值。它们的含义分别是:

  • 参数 daemonize 表示,是否要设置 Redis 以守护进程方式运行;
  • 参数 supervised 表示,是否使用 upstart 或是 systemd 这两种守护进程的管理程序来管理 Redis。

fork 函数的不同返回值,其实代表了不同的含义,具体来说:

  • 当返回值小于 0 时,此时表明 fork 函数执行有误;
  • 当返回值等于 0 时,此时,返回值对应的代码分支就会在子进程中运行;
  • 当返回值大于 0 时,此时,返回值对应的代码分支仍然会在父进程中运行。

从 bio.c 文件学习 Redis 的后台线程

main 函数在初始化过程最后调用的 InitServerLast 函数。InitServerLast 函数的作用是进一步调用 bioInit 函数,来创建后台线程,让 Redis 把部分任务交给后台线程处理。

BIO_NUM_OPS 表示的是 Redis 后台任务的类型有三种。而 BIO_CLOSE_FILE、BIO_AOF_FSYNC 和 BIO_LAZY_FREE,它们分别表示三种后台任务的操作码,这些操作码可以用来标识不同的任务。

  • BIO_CLOSE_FILE:文件关闭后台任务。
  • BIO_AOF_FSYNC:AOF 日志同步写回后台任务。
  • BIO_LAZY_FREE:惰性删除后台任务。

bioInit 函数:设置线程属性并创建线程

在完成了初始化之后,接下来,bioInit 函数会先通过 pthread_attr_t 类型的变量,给线程设置属性。然后,bioInit 函数会调用 pthread_create 函数来创建线程。

int  pthread_create(pthread_t *tidp, const  pthread_attr_t *attr,
( void *)(*start_routine)( void *), void  *arg);

pthread_create 函数一共有 4 个参数,分别是:

  • *tidp,指向线程数据结构 pthread_t 的指针;
  • *attr,指向线程属性结构 pthread_attr_t 的指针;
  • *start_routine,线程所要运行的函数的起始地址,也是指向函数的指针;
  • *arg,传给运行函数的参数。

bioCreateBackgroundJob 函数:创建后台任务

bioCreateBackgroundJob 函数的原型如下,它会接收 4 个参数,其中,参数 type 表示该后台任务的类型,剩下来的 3 个参数,则对应了后台任务函数的参数,如下所示:

void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3)

bioCreateBackgroundJob 函数在执行时,会先创建 bio_job,这是后台任务对应的数据结构。然后,后台任务数据结构中的参数,会被设置为 bioCreateBackgroundJob 函数传入的参数 arg1、arg2 和 arg3。

最后,bioCreateBackgroundJob 函数调用 listAddNodeTail 函数,将刚才创建的任务加入到对应的 bio_jobs 队列中,同时,将 bio_pending 数组的对应值加 1,表示有个任务在等待执行。

Redis 后台线程的创建和运行机制。简单来说,主要是以下三个关键点:

  1. Redis 是先通过 bioInit 函数初始化和创建后台线程;
  2. 后台线程运行的是 bioProcessBackgroundJobs 函数,这个函数会轮询任务队列,并根据要处理的任务类型,调用相应函数进行处理;
  3. 后台线程要处理的任务是由 bioCreateBackgroundJob 函数来创建的,这些任务创建后会被放到任务队列中,等待 bioProcessBackgroundJobs 函数处理。

此文章为10月Day12学习笔记,内容来源于极客时间《Redis 源码剖析与实战》