- 博客(127)
- 资源 (1)
- 收藏
- 关注
原创 Redis 源码学习之快速列表 quicklist
应用 Redis中是采用sdlist和ziplist来实现quicklist的,其中sdlist充当map中控器的作用,ziplist充当占用连续内存空间数组的作用。quicklist本身是一个双向无环链表,它的每一个节点都是一个ziplist。为什么这么设计呢? 双向链表在插入节点上复杂度很低,但它的内存开销很大,每个节点的地址不连续,容易产生内存碎片。 ziplist是存储在一段连续的内存上,存储效率高,但是它不利于修改操作,插入和删除数都很麻烦,复杂度高,而且其需要频繁的申请释放内存,特别是zipl
2021-09-13 16:11:49
367
原创 Redis 源码学习之 字符串 t_string
字符串概述 字符串是Redis中最为常见的数据存储类型,其底层实现是简单动态字符串sds,因此,该字符串类型是二进制安全的,这就意味着它可以接受任何格式的数据。另外,Redis规定,字符串类型最多可以容纳的数据长度为512M 提供了检测函数,来检测字符串键的大小 /* * 检查给定字符串长度 len 是否超过限制值 512 MB * * 超过返回 REDIS_ERR ,未超过返回 REDIS_OK * * T = O(1) */ static int checkStringLength(clie
2021-09-11 22:00:13
314
原创 Redis 源码学习之 对象
对象使用 使用对象一个好处是:我们可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率 对象系统还实现了基于引用计数技术的内存回收机制 Redis 通过引用计数技术实现对象共享机制 Redis 的对象带有访问时间记录信息 Redis 使用对象来表示数据库中的键和值 RedisObject数据结构 typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsign
2021-09-10 22:42:57
330
原创 Redis 源码学习之压缩列表
应用 压缩列表(ziplist)是由 一系列特殊编码的内存块构成的列表,其是Redis的列表建和哈希键的底层实现之一 ziplist可以用来存放字符串或者整数,其存储数据的特点是:比较小的整数或比较短的字符串。Redis的列表建,哈希键,有序集合的底层实现都用到了ziplist 压缩列表是为了节约内存而开发的 Ziplist 是为了尽可能地节约内存而设计的特殊编码双端链表 Ziplist 允许在列表的两端进行 O(1) 复杂度的 push 和 pop 操作 数据结构 Redis的ziplist结构由三大
2021-09-10 22:02:22
287
2
原创 Redis源码学习之 整数集合
intset应用 Redis在这种小数据量的条件下,会使用内存映射来代替内部数据结构。这就使得整数集合(intset)和压缩(ziplist)这两类节省内存的数据结构应运而生了 整数集合是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现 整数集合的底层实现为数组,这个数组有序、无重复的方式保存集合元素,在有需要时,程序会根据新添元素的类型,改变这个数组的类型 整数集合只支持升级操作,不支持降级操作 intset的数据结构 如
2021-09-10 20:58:59
181
原创 Redis 源码学习之跳跃表
跳跃表的应用 跳跃表的性质; (1) 由很多层结构组成; (2)每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点; (4) 最底层的链表包含了所有的元素; (5) 如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集); (6) 链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点; 跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节
2021-09-10 17:57:05
174
原创 redis 源码学习 之 字典dict
字典应用 Redis的数据库就是使用字典作为底层实现的,对数据库的增、删、查、改都是建立在对字典的操作上。此外,字典还是Redis中哈希键的底层实现,当一个哈希键包含的键值对比较多,或者键值对中的元素都是比较长的字符串时,Redis就会使用字典作为哈希键的底层实现 Redis中的字典采用哈希表作为底层实现 dict数据结构 实现了一个内存哈希表, 它支持插入、删除、替换、查找和获取随机元素等操作。哈希表会自动在表的大小的二次方之间进行调整。 键的冲突通过链表来解决 1、哈希表节点(dictEntry) 字典
2021-09-09 11:24:41
271
原创 redis 源码学习之双端链表sdlist
sdlist主要作用 主要用在实现列表键、事务模块保存输入命令和服务器模块,订阅模块保存多个客户端等 sdlist的数据结构 Redis为双端链表的每一个节点定义了如下的结构体 // 链表节点定义 typedef struct listNode { struct listNode *prev; // 指向前一个节点 struct listNode *next; // 指向后一个节点 void *value; // 节点值 } listNode; 双端链表的迭代器的定义: 单向迭
2021-09-08 21:45:07
228
原创 redis 源码学习之动态字符串
字符串数据结构总结 Redis没有使用C语言的字符串结构,而是自己设计了一个简单的动态字符串结构sds。它的特点是:可动态扩展内存、二进制安全和与传统的C语言字符串类型兼容 sds数据结构定义 Redis 专门设计了 SDS 数据结构,在字符数组 的基础上,增加了字符数组长度和分配空间大小等元数据 typedef char *sds; struct sds{ int free; //保存未使用的长度空间 int len; //保存已经分配的长度空间,不包括’\0’, } struct sdshdr{
2021-09-08 20:42:48
163
原创 redis源码学习之分配内存
1、redis 总体概况 Redis在内存分配方面,仅仅是对系统的malloc/free做了一层简单的封装,然后加上了异常处理功能和内存统计功能。其实现主要在zmalloc.c和zmalloc.h文件中 2、功能函数 void *zmalloc(size_t size); // 调用zmalloc函数,申请size大小的空间 void *zcalloc(size_t size); // 调用系统函数calloc申请内存空间 void *zrealloc(void *ptr, size_t size); //
2021-09-08 15:20:11
532
原创 MySQL知识总结
1、一条MYSQ查询语句L的执行过程: 连接器:连接器负责跟客户端建立连接、获取权限、维持和管理连接。 问题:有些时候 MySQL 占用内存涨得特别快? 原因:MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。 解决:通过执行 mysql_reset_connection 来重新初始化连接资源 查询缓存 之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的 语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这
2021-09-06 17:03:01
189
原创 MySQL之事务原理
1、定义; 事务是访问并更新数据库各种数据的一个程序执行单元 2、锁 1、类型 共享锁 事务读操作加的锁,对某一行加锁 排他锁 事务删除或更新加的锁,对莫i一行加锁 意向共享锁 对一张表中某几行加的共享锁 意向排他锁 对一张表中某几行加的排他锁、 3、 MVCC机制 多版本并发控制:用来实现一致性的非锁定读;非锁定读是指不需要等待访问的行上排他锁(写锁)的释放,;在读已提交和刻重复读下,innodb使用MVCC;然后对于快照数据的定义不同,在读已提交的隔离级别下,对于快照数据总是读取事务
2021-07-31 22:24:29
150
原创 MySQL索引
1、B-树和B+树 是多路平衡搜索树, B树找到一定范围的节点采用中序遍历 2、⼀个m阶B树具有如下特征 根结点⾄少有两个⼦⼥ 每个中间节点都包含k-1个元素和k个孩⼦,其中 m/2 <= k <= m 每⼀个叶⼦节点都包含k-1个元素,其中 m/2 <= k <= m; 所有的叶⼦结点都位于同⼀层 每个节点中的元素从⼩到⼤排列,节点当中k-1个元素正好是k个孩⼦包含的元素的值域划分;(可以理解为k-1元素,k个指针) 下图为5阶的B树 3、为什么索引采用的索引结构是B=树
2021-07-31 21:11:25
152
原创 数据结构之平衡树 插入删除操作(包括代码)
1、左旋 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变 2、右旋 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变 #include<iostream> using namespace std; typedef struct BiTNode{ int data; int height; //高度,表示以当前结点为根的子树的高
2021-07-31 17:51:56
335
原创 手写 实现线程池
1、什么是线程池? 线程池如何实现? 1.如何从线程池里面拿一个线程 2.如何把线程返回给线程池 3.线程池里面控制线程数量 1、 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define LL_ADD(item, list) do { \ item->prev = NULL; \ item->next =
2021-07-30 13:28:43
243
原创 红黑树插入操作
1、插入 #include<stdlib.h> #includde<stdio.h> typedef struct Node{ int key; int color; 0表示红,黑表示1 struct Node*lchild,*rchild; }Node; Node __NIL; #define NIL(&__NIL) __atrribute__((constructor)) void init_NIL() { NIL->key = 0; NIL->
2021-07-30 10:46:43
220
原创 Linux网络编程之epoll反应堆模型
epoll API epoll_create(); — int epfd = epoll(10); — epfd(句柄) struct epoll_event events; events.events = EPOLLIN; events.data.fd = lfd; epoll_ctl(); — epoll(epfd, EPOLL_CTL_ADD, lfd, &events); op: EPOLL_CTL_ADD/MOD/DEL events: EPOLLIN/OUT/
2021-07-04 16:09:48
304
2
原创 Linux网络编程之epoll函数
1、epoll API 1、 epoll_create函数 函数作用 创建一个epoll句柄,参数size用来告诉内核监听的文件描述符的个数,跟内存大小有关。 函数原型 #include <sys/epoll.h> int epoll_create(int size) size:监听数目 返回值: 返回一个文件描述符,这个文件描述符指向一颗平衡二叉树的树根 Linux内核里面是红黑树 2、epoll_ctl 函数 函数作用 控制某个epoll监控的文件描述符上的事件:注册、
2021-06-21 18:04:12
448
原创 Linux网络编程之poll函数
1、poll函数详解 头文件 #include <poll.h> 函数原型 int poll(struct pollfd fds, nfds_t nfds, int timeout); fds :结构体数组的首地址 struct pollfd { int fd; / 文件描述符 / short events; / 监控的事件 / short revents;/ 监控事件中满足条件返回的事件 */ }; events: POLLIN(读事件)、POLLOUT(写事件
2021-06-21 18:03:59
678
原创 Linux 网络编程之select函数
1、什么是I/O多路转接技术: 先构造一张有关文件描述符的列表, 将要监听的文 件描述符添加到该表中 然后调用一个函数,监听该表中的文件描述符,直到 这些描述符表中的一个进行I/O操作时,该函数才 返回 1.该函数为阻塞函数 2.函数对文件描述符的检测操作是由内核完成的 在返回时,它告诉进程有多少(哪些)描述符要进行 不再由应用程序自己监视客户端连接,取而代之由内核替应用程序监视文件。 2、 IO多路转接 - select select返回的是发生I/O操作文件描述符的总数量,传出来的文件描述符表是
2021-06-21 13:12:31
394
原创 Linux网络编程之多线程并发服务器
思路: 1、主控线程等待接受连接请求 2、子线程 负责通信 多线程并发服务器伪代码: typedef struct sockInfo{ pthread_t id; int fd; struct sockaddr_in addr; }SockInfo; void work(void * arg) { while() { //打印客户端ip和port; read(); write(); } } int main() { //监听 int lfd = sock
2021-06-21 09:40:33
222
原创 linux网络编程之多进程并发服务器
1、父进程负责等待连接请求,子进程负责和客户端通信,每次有一个连接请求,就创建一个子进程和客户端进行通信 使用多进程的方式,解决服务器多连接的问题: 1、共享 读时共享,写时复制 父子进程共享文件描述符,内存映射区 2、父进程的角色? 等待客户端连接,有连接,创建一个子进程 关闭 用于通信的文件描述符 3、子进程的角色? 和客户端通信 关闭监听的文件描述符 4、创建的进程的个数有限制吗 一个进程最多有1024个文件描述符 有限制,受硬件的限制 5、子进程资源回收 wait/waitpid 信
2021-06-20 22:28:58
288
1
原创 linux 系统编程之信号量
信号量 信号量初始化时为n,也就是说可以指定任意值 -一 个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步 既可以用于线程同步又可以用于进程同步 主要应用函数: sem_init函数 sem_destroy函数 sem_wait函数 sem_trywait函数 sem_timedwait函数 sem_post函数 以上6 个函数的返回值都是:成功返回0, 失败返回-1,同时设置errno。 sem_t类型,本质仍是
2021-06-20 17:54:55
271
原创 Linux系统编程之条件变量
条件变量 条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用 主要应用函数: pthread_cond_init函数 pthread_cond_destroy函数 pthread_cond_wait函数 pthread_cond_timedwait函数 pthread_cond_signal函数 pthread_cond_broadcast函数 以上6 个函数的返回值都是:成功返回0, 失败直接返回错误号。 pthread_cond_t类型 结构体类型 用于定义条件变量 :pth
2021-06-20 17:09:57
337
原创 Linux系统编程之读写锁
读写锁 读写锁状态: 一把读写锁具备三种状态: 1. 读模式下加锁状态 (读锁) 2. 写模式下加锁状态 (写锁) 3. 不加锁状态 读写锁特性: 读写锁是“写模式加锁”时, 解锁前,所有对该锁加锁的线程都会被阻塞。 读写锁是“读模式加锁”时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞。 读写锁是“读模式加锁”时, 既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。读锁、写锁并行阻塞,写锁优先级高 主要应用函数: pthrea
2021-06-20 16:18:58
520
原创 Linux系统编程之死锁
死锁 **1. 线程试图对同一个互斥量A加锁两次。** 当线程对一个互斥量加锁两次:会发生 死锁 分析:线程A对一个互斥量加锁,访问结束后,又进行加锁,会发生阻塞现象,等着线程A解锁,但是线程A 进行加锁操作,一直阻塞在那里,所以发生了死锁 代码如下所示: #include <iostream> #include <thread> #include <mutex> #include <unistd.h> using namespace std; int
2021-06-20 15:21:08
206
原创 Linux系统编程之互斥量
思想: 每个线程在对****资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁 互斥锁实质上是操作系统提供的一把“建议锁”(又称“协同锁”),建议程序中有多线程访问共享资源的时候使用该机制。但,并没有强制限定。 主要应用函数: pthread_mutex_init函数 pthread_mutex_destroy函数 pthread_mutex_lock函数 :阻塞发等待 pthread_mutex_trylock函数 pthread_mutex_unlock函数 pthread_mutex_t 类型,
2021-06-20 14:49:12
214
原创 linux系统编程之线程属性
1. 初始化线程属性 函数原型:int pthread_attr_init(pthread_attr_t *attr); . 成功:0;失败:错误号 attr是传出参数 typedef struct { int etachstate; //线程的分离状态 int schedpolicy; //线程调度策略 struct sched_param schedparam; //线程的调度参数 int inheritsched; //线程的继承性 int sc
2021-06-20 14:11:57
171
原创 linux系统编程之杀死线程
pthread_cancel函数 杀死(取消)线程 其作用,对应进程中 kill() 函数。 函数原型:int pthread_cancel(pthread_t thread); 成功:0;失败:错误号 【注意】:线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。 取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write… 执行命令man 7 pthreads可以查看具备这些取消
2021-06-20 12:34:44
4646
原创 Linux网络编程之C/S模型
1、C/S模型 实现的功能:从客户端读取字符,然后将每个字符转换 成大写并返回客户端 服务器端:等待连接,连接后从客户端读取数据进行处理,然后返回客户端,并且循环等待客户端连接 server.c #include<stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h
2021-06-18 17:16:08
331
原创 linux网络编程之本地套接字通信
本地套接字 伪文件 即可采用TCP通信又可采用UDP通信 采用TCP通信流程如下 服务器端 创建套接字 int lfd=socket(AF_UNIX,SOCK_STREAM,0) 绑定一个套接字文件 struct sockaddr_un serv; serv.sun_family=AF_UNIX; strcpy(serv.sun_path,“server.socket”);------现在还不存在 bind(lfd,(struct sockaddr*)&serv,len);------绑
2021-04-20 10:51:54
264
原创 Linux网络编程之组播通信
组播 适用于局域网和广域网 结构体 struct ip_mreqn { //组播组的IP地址 struct in_addr imr_multiaddr; //本地某一网络设备接口的IP地址 struct in_addr imr_interface; int imr_ifindex;//网卡编号 }; struct in_addr { in_addr_t s_addr; } 代码 server.c #include <stdio.h> #include <unistd.h> #i
2021-04-19 23:29:50
428
原创 linux网络编程之UDP通信
udp面向无连接不安全保文传输 服务器端: 创建套接字 绑定ip和端口:bind() struct sockaddr—服务器 通信 接受数据:recvfrom ssize_t recvfrom(int sockfd,voidbuf,size_t len,int flag,struct sockaddrsrc_addr,socklen_t*addrlen) fd—文件描述符 buf—接受数据缓冲区 len—buf的最大容量 flags—0 src_addr—另一端的ip和端口,传出参数 ad
2021-04-19 22:01:25
181
原创 Linux 网络编程之UDP实现广播
广播IP:192.168.42.255 利用setsockopt函数给sockfd开放广播权限 server.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <net/if.h> #define SE
2021-04-19 20:08:15
1091
2
原创 Linux系统编程之线程退出
pthread_exit函数 功能:将单个线程退出 void pthread_exit(void *retval); 参数:retval表示线程退出状态,通常传NULL #include<stdio.h> #include<pthread.h> #include<unistd.h> #include<stdlib.h> void *thrd_func(void*arg) { prrintf("In thread;thread id=%lu,pid=%d
2021-04-19 11:07:06
228
原创 Linux系统编程之一个进程最多能创建多少个线程
#include<string.h> #include<stdlib.h> #include<pthread.h> void *tfn(void *arg) { while(1) { sleep(1); } } int main(void) { pthread_t tid; int ret,count=1; for(;;) { ret=pthread_tcreate(&tid,NULL,tfn,NULL); if(ret
2021-04-19 10:52:26
232
原创 Linux系统编程之回收线程
pthread_join函数 功能:阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数 nt pthread_join(pthread_t thread, void **retval); 返回值:成功:0;失败:错误号 参数:thread:线程ID (【注意】:不是指针);retval:存储线程结束状态。 回收线程代码: #include<pthread.h> #include<stdlib.h> #include<stdio.h>
2021-04-15 23:24:40
165
原创 linux系统编程之创建线程、循环创建N个线程、线程共享全局变量
pthread_create函数 功能:创建一个新线程。 其作用,对应进程中fork() 函数 Int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) 返回值:成功:0; 失败:错误号 -----Linux环境下,所有线程特点,失败均直接返回错误号 参数: pthread_t:当前Linux中可理解为:typedef
2021-04-15 22:08:26
622
原创 linux系统编程之pause函数
功能:利用pause函数和alarm函数实现sleep函数功能 #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<signal.h> #include<errno.h> void catch_sigalrm(int signo) { ; } unsigned int mysleep(unsigned int seconds) { int ret; struc
2021-04-14 14:38:52
883
原创 Linux系统编程之signal函数
#include<signal.h> #include<stdlib.h> #include<errno.h> #include<unistd.h> #include<unistd.h> typedef void(* sighandler_t)(int); void catchsigint(int sigo) { printf("--------catch\n"); } int main(void) { sighandler_t han
2021-04-14 10:50:00
208
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅