主要看下redis是怎么使用多线程的
先说明下redis也是多线程的.但是redis的主线程处理业务.而其他三个线程跟主要功能是关系不到的
redis的三个线程主要是做什么
初始化入口
void initServer(void) { ... bioInit(); ... }
初始化后redis其他后台线程.
void bioInit(void) { pthread_attr_t attr; pthread_t thread; size_t stacksize; int j; for (j = 0; j < REDIS_BIO_NUM_OPS; j++) { pthread_mutex_init(&bio_mutex[j],NULL); pthread_cond_init(&bio_condvar[j],NULL); bio_jobs[j] = listCreate(); bio_pending[j] = 0; } pthread_attr_init(&attr); pthread_attr_getstacksize(&attr,&stacksize); if (!stacksize) stacksize = 1; while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2; pthread_attr_setstacksize(&attr, stacksize); for (j = 0; j < REDIS_BIO_NUM_OPS; j++) { void *arg = (void*)(unsigned long) j; if (pthread_create(&thread,&attr,bioProcessBackgroundJobs,arg) != 0) { redisLog(REDIS_WARNING,"Fatal: Can't initialize Background Jobs."); exit(1); } bio_threads[j] = thread; } }
初始化三类线程. 这三类线程被认为是后台执行.不影响主线程
- BIO_CLOSE_FILE . 关闭重写之前的aof文件.
- BIO_AOF_FSYNC . 定时刷新数据到磁盘上.
- BIO_LAZY_FREE . 惰性删除过期时间数据
redis为了保证其高效.一些比较耗时的动作会起线程或者进程来完成.不会阻塞在业务主线程上.
使用多线程的特点
- 创建3个线程.这个三个线程的功能互不影响
- 每个线程都有一个工作队列.主线程生产任务放到任务队里.这三个线程消费这些任务.
- 任务队列和取出消费的时候都得加锁.防止竞争
- 使用条件变量来等待任务.以及通知
static list *bio_jobs[REDIS_BIO_NUM_OPS];
bio_jobs是一个双端链表结构
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_condvar[type]); pthread_mutex_unlock(&bio_mutex[type]); }
当有任务的时候.先把任务丢到redis工作队列里.这里记得加锁
void *bioProcessBackgroundJobs(void *arg) { struct bio_job *job; unsigned long type = (unsigned long) arg; sigset_t sigset; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&bio_mutex[type]); sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); if (pthread_sigmask(<