php 多线程处理redis,redis的多线程

目录

先说明下redis也是多线程的.但是redis的主线程处理业务.而其他三个线程跟主要功能是关系不到的

redis的三个线程主要是做什么

初始化入口void initServer(void) {

...

bioInit();

...

}

初始化后redis其他后台线程.void bioInit(void) {

pthread_attr_t attr;

pthread_t thread;

size_t stacksize;

int j;

/* Initialization of state vars and objects

*

* 初始化 job 队列,以及线程状态

*/

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;

}

/* Set the stack size as by default it may be small in some system

*

* 设置栈大小

*/

pthread_attr_init(&attr);

pthread_attr_getstacksize(&attr,&stacksize);

if (!stacksize) stacksize = 1; /* The world is full of Solaris Fixes */

while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2;

pthread_attr_setstacksize(&attr, stacksize);

/* Ready to spawn our threads. We use the single argument the thread

* function accepts in order to pass the job ID the thread is

* responsible of.

*

* 创建线程

*/

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;

/* 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);

pthread_mutex_lock(&bio_mutex[type]);

/* Block SIGALRM so we are sure that only the main thread will

* receive the watchdog signal. */

sigemptyset(&sigset);

sigaddset(&sigset, SIGALRM);

if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))

redisLog(REDIS_WARNING,

"Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno));

while(1) {

listNode *ln;

/* The loop always starts with the lock hold. */

if (listLength(bio_jobs[type]) == 0) {

pthread_cond_wait(&bio_condvar[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 == REDIS_BIO_CLOSE_FILE) {

close((long)job->arg1);

} else if (type == REDIS_BIO_AOF_FSYNC) {

aof_fsync((long)job->arg1);

} else {

redisPanic("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]--;

}

}操作前先上锁

从工作任务里取任务

解锁

执行业务逻辑

执行完上锁.重新pthread_cond_wait

条件变量

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;

另一个线程使"条件成立"(给出条件成立信号)。

==为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起==

pthread_cond_wait原理

就是说pthread_cond_wait(pthread_cond_t cond, pthread_mutex_tmutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock()。

==pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁==

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368102.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux内核删不掉,linux 删除内核文件,未能启动,修复方法 CDROM与网络法

当缺少 /boot 内核文件vmlinuz-2….initramfs-2…此时只能借助 光盘 CDROM 来引导生成进入 RESCUE 模式1 chroot /mnt/sysimagemount /dev/cdrom /mnt/cdromcd /mnt/cdromcd isolinux cp vmlinuz /boot/按照…

阿卡vs风暴

我最近在Twitter的Storm上工作了一段时间&#xff0c;这让我想知道&#xff0c;它与另一个高性能的并发数据处理框架Akka相比如何 。 什么是Akka和Storm&#xff1f; 让我们从两个系统的简短描述开始。 Storm是一个分布式实时计算系统。 在Storm集群上&#xff0c;您执行拓扑 …

清除浮动方法解析

清除浮动方法解析 清除浮动带来的额外影响 如果对于浮动不熟悉的同学&#xff0c;可以看看介绍float的文章。传送门&#xff1a;CSS float 我们知道&#xff0c;在一个父元素内如果遇到某个浮动元素&#xff0c;此时父元素的高度会发生塌陷。针对父元素高度塌陷的问题&#xff…

进程间的通信----管道

前提&#xff1a;本文是基于Linux系统下的学习 用户态的进程是如何组织的呢&#xff1f;所有的用户态进构成了一棵树。进程树。 进程树的树根是init.也就是1号进程。是用户态进程的祖宗进程。如何查看进程树&#xff1f;pstree 进程之间的关系 父子进程和兄弟进程查看进程的信息…

web项目启动时,自动执行代码的几种方式

在项目开发过程中&#xff0c;往往需要一些功能随着项目启动而优先启动&#xff0c;下面我总结几种方式&#xff08;非spring boot&#xff09; spring boot的参考 spring boot 学习之路9 (项目启动后就执行特定方法) 方式一&#xff1a; ServletContextListener监听器&#…

设计模式:状态

本文将介绍状态设计模式 。 它是行为设计模式之一 。 您无需了解许多理论即可了解模式的主要概念。 该文章将分为几个部分&#xff0c;在其中我将提供有关需要应用该模式的情况&#xff0c;它所具有的利弊以及用法示例的信息。 有时&#xff0c;当对象的内部状态更改时&#…

Linux内核锁实现原理,linux 大内核锁原理

大内核锁(BKL)的设计是在kernel hacker们对多处理器的同步还没有十足把握时&#xff0c;引入的大粒度锁。他的设计思想是&#xff0c;一旦某个内核路径获取了这把锁&#xff0c;那么其他所有的内核路径都不能再获取到这把锁。自旋锁加锁的对象一般是一个全局变量&#xff0c;大…

Sass学习日志

一、什么是SASS SASS是一中CSS的开发工具&#xff0c;提供了许多便利的写法&#xff0c;大大节约了设计者们的时间&#xff0c;使得CSS的开发&#xff0c;变得简单和可维护。本文总结了SASS的主要方法。我们的目标是&#xff0c;有了这篇文章&#xff0c;日常的一般使用就不需…

ptyhon中文本挖掘精简版

import xlrd import jieba import sys import importlib import os #python内置的包&#xff0c;用于进行文件目录操作&#xff0c;我们将会用到os.listdir函数 import pickle #导入cPickle包并且取一个别名pickle #持久化类 import random import numpy as np …

[UWP]了解模板化控件(9):UI指南

[UWP]了解模板化控件(9)&#xff1a;UI指南 原文:[UWP]了解模板化控件(9)&#xff1a;UI指南1. 使用TemplateSettings统一外观 TemplateSettings提供一组只读属性&#xff0c;用于在新建ControlTemplate时使用这些约定的属性。 譬如&#xff0c;修改HeaderedContentControl的Co…

Java的反射API

如果您曾经问​​过自己以下问题&#xff1a; –“如何在字符串中仅包含其名称的方法调用&#xff1f;” –“如何动态列出类中的所有属性&#xff1f;” –“如何编写一种将任何给定对象的状态重置为默认值的方法&#xff1f;” 然后您可能已经听说过Java的Reflection API…

linux服务器基本常识,服务器搭建-Linux基础知识

服务器搭建还是需要一些Linux知识的&#xff0c;这节就聊点基础的。文件权限操作查看权限Linux中每个文件对每个用户来说都有对应的权限&#xff0c;在任一路径中输入ll就可以查看这些信息&#xff1a;rootip-*** /usr/local # lltotal 32Kdrwxr-xr-x 2 root root 4.0K Jan 14 …

mysql基本命令入门

背景 作为一个前端&#xff0c;重新学习后台相关知识&#xff0c;记录下自己遇到及用到的命令及爬坑经验。 基本命令 1.创建数据库 create database 数据库名称 eg: create database test //创建一个名为test的数据库 2.查看所有数据库 show databases 3.选择某一个数据库 use …

不完善迷你计算器

html代码&#xff1a; <!DOCTYPE html PUBspanC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns"http://www.w3.org/1999/xhtml"><head><meta http-e…

LINQ和Java

LINQ已经非常成功&#xff0c;但在.NET生态系统中也引起了争议。 许多人正在Java世界中寻找可比的解决方案。 为了更好地理解什么是可比的解决方案&#xff0c;让我们看一下LINQ解决的主要问题&#xff1a; 查询语言通常是具有许多关键字的声明性编程语言。 它们提供的控制流元…

怎样 测试 某个 端口 是否打开

我们一般最常见的工具是telnet&#xff0c;但是telnet使用的是tcp协议&#xff0c;换句话说telnet只能检测tcp的这个端口打开了没。 方法很简单&#xff0c;假设我们要看192.192.193.211这个IP的tcp 22端口是否打开&#xff0c;则运行telnet 192.192.193.211 22 来查看 如果cen…

linux用户空间注册按键事件,linux下获取按键响应事件

1、问题通过一个死循环将读取键盘对应的设备文件将触发键盘事件在屏幕上打印出来&#xff0c;按esc退出程序代码是在unbuntu10.04编译执行通过的2、input_event描述在Linux内核中&#xff0c;input设备用input_dev结构体描述&#xff0c;使用input子系统实现输入设备驱动的时候…

CSS实现单行与多行文字省略(truncation)

在上一篇文章小div布局之卡片堆叠&#xff08;card-stacking&#xff09;中有多行文字溢出省略的效果&#xff0c;这篇文章就对这种效果&#xff08;包括单行文字溢出省略&#xff09;的实现做个简单的记录&#xff0c;以防自己忘记。具体来说&#xff0c;就是要实现这种文字排…

位运算的使用例子

class Data { public:enum Permission{allowSelect 1 << 0,allowUpdate 1 << 1,allowInsert 1 << 2,allowDelete 1 << 3}; public:Data():flag(0){};~Data(){};/*添加某权限*/void enable(int permission){flag | permission;}/*删除某权限*/void…

事务性Lucene

许多用户不喜欢Lucene API的事务性语义&#xff0c;以及这在搜索应用程序中如何有用。 首先&#xff0c;Lucene实现了ACID属性&#xff1a; 一个 tomicity&#xff1a;当您在更改&#xff08;添加&#xff0c;删除文件&#xff09; IndexWriter会话&#xff0c;然后提交&#…