- 博客(67)
- 收藏
- 关注
原创 无锁队列ringbuff实现以及性能
以上场景对于有锁队列和无锁队列都可以使用的,但还如果对性能要求比较高,比如需要达到上万ops,就可以考虑优先使用无锁队列。相反如果性能达不到这么高使用有锁队列和无锁队列性能差别并不大,但是有锁队列实现会更加简单。以同样的数据结构(环形队列)实现一个有锁的队列,进行对比测试,两者的区别就在于一个加锁一个无锁,消费者在取出数据后会进行1000 次 empty loop。系统:Debian x86_64虚拟机,4核4G。本文采用的是循环队列的实现方式。
2023-06-29 16:48:13
416
原创 无锁数据结构 ---- 栈实现
无锁数据结构,即不使用任何锁机制实现可以多线程并发访问的数据结构。相比较有锁数据结构有如下优缺点:实现无锁数据结构,最好不要一开始就直接想着去如何实现无锁数据结构,因为这样能难考虑全面,可以以最简单的单线程栈开始,然后慢慢修改成无锁栈,下面以最简单的单线栈开始。
2023-06-21 17:41:48
1217
原创 常用设计模式之单例模式
这里声明了一个Single的单例类,类中有两个与其它类不同的地方,一个就是它的构造函数是私有的,这样做的目的就是防止外界调用构造函数,而只要外界不能调用构造函数那么就不能对该类进行实例化(类内可以访问私有的构造函数所以只能类内实例化)。:某些情况下,造成内存浪费,因为对象未被使用的情况下就会被初始化,如果一个项目中的类多达上千个,在项目启动的时候便开始初始化可能并不是我们想要的。的时候确保当前的对象时没有被实例过的,因为上锁操作对性能是有影响的,所以这里会有一个双重的判定。而这只是单例类的一种懒汉式写法。
2023-06-06 17:56:30
535
原创 虚拟内存原理介绍
我们知道系统中的所有进程都是共享CPU和主存资源,但这样就会存在一个问题,这么多进程怎么知道主存上的一块内存是已分配给了其它进程还是空闲状态。所有我们需要一种机制来专门负责操作系统上内存资源的管理,而虚拟内存就充当这样一个角色。虚拟内存是操作系统提供的一种内存管理技术,是对主存的一种抽象。由硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间。
2023-06-06 16:13:16
1032
原创 C++内存序、屏障和原子操作
其中,std::atomic_thread_fence和std::atomic_signal_fence是用于控制内存访问顺序的栅栏,std::thread::join是用于等待其他线程完成的栅栏。保证该操作之前写入的值对其它线程都是可见,这和写屏障功能很像:把CPU高速缓存中的数据同步到主存和其它CPU高速缓存中(其实是发送了一个更新指令消息到其它CPU的invalidate queue中),即该操作写入一个值后其它线程读取该值一定是之前写入的值,满足可见性。
2023-06-06 16:12:34
1143
原创 线程池原理(C和C++实现)
当并发数很多的时候,并且每个线程执行时间很短的任务,这样就会频繁创建线程,而这样的频繁创建和销毁线程会大大降低系统的执行效率。对于这种场景我们可以使用线程池来复用之前创建的线程,降低线程的频繁创建和销毁工作,达到提高执行效率的目的。
2023-05-24 23:00:50
955
转载 LVM 创建流程
1. 文件系统的扩展和缩减文件系统在创建时是分成多个块组(block group)的,因此文件系统的增减实际上就是以增减块组的方式实现的。在linux中,ext系列格式的文件系统是可以扩展和缩减的,而xfs格式的目前只能扩展1)扩展文件系统①先确定扩展的目标大小,并确保对应卷组中有足够的空闲空间可用。如果不够,可先通过vgextend命令扩大卷组容量# vgextend myvg /dev/sda7②扩展逻辑卷# lvextend -L 4G /dev/myvg/mylv③扩展文件系统r
2021-09-25 15:18:09
637
原创 LVM基础介绍
一、LVM介绍LVM(Logical Volume Manager),即逻辑卷管理,是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管理的灵活性。通过LVM系统管理员可以轻松管理磁盘分区,如:将若干个磁盘分区连接为一个整块的卷组(volume group),形成一个存储池。管理员可以在卷组上随意创建逻辑卷组(logical volumes),并进一步在逻辑卷组上创建文件系统。管理员通过LVM可以方便的调整存储卷组的大小,并且可以对磁盘存储按照组的方式
2021-09-25 14:56:39
685
原创 linux NFS安装 libnfs使用
1. 介绍NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问远程共享目录,就像访问本地磁盘一样。NFS 只是一种文件系统,本身并没有传输功能,是基于 RPC(远程过程调用)协议实现的,采用 C/S 架构。2. 安装Ubuntu$ sudo apt-get install nfs-kernel-server # 安装 NFS服务器端$ sudo apt-get install nfs-common
2021-09-22 20:23:56
1789
转载 详解RocksDB如何通过组提交提升性能
从维基百科的词条,我们可以看到:ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。特别地,为了保证事务的原子性和持久性,在对数据库内存中维护的各种数据结构修改之前,会将该事务的对数据库的所有操作信息先写入磁盘中日志文件,这个过程被称为预写日志(Write-Ahe
2020-10-14 23:06:44
682
1
原创 rocksdb写流程DBImpl::WriteImpl()源代码分析
文章结构1. WriteThread的状态2. write_group结构3. 写过程WriteImpl()函数源码分析1. WriteThread的状态写线程WriteThread会有几种状态,在写memtable的过程中通这几种状态来决定当前w当前执行到哪儿了,下一步该怎么执行。 enum State : uint8_t { // The initial state of a writer. This is a Writer that is // waiting in Joi
2020-10-13 17:23:51
959
2
转载 C++匿名函数使用方法
文章目录1、匿名函数的使用2、什么是捕获列表?3、一些”废话“3.1、介绍Lambda3.2、Lambda捕获列表1、匿名函数的使用匿名函数的基本语法为://[捕获列表](参数列表)->返回类型{函数体}int main(){ auto Add = [](int a, int b)->int { return a + b; }; std::cout << Add(1, 2) << std::endl; return 0;}上述代码便会输出3,
2020-08-07 16:42:24
1699
2
原创 QT 多线程的两种实现方法
文章目录源文件类实现方法 1实现方法 2总结源文件类widget类为主线程,mythread为待创建的子线程类点击按钮线程开始执行(针对方法一,方法二忽略图形界面)实现方法 1widget.h#include <QWidget>#include <QThread>#include "mythread.h"class Widget : public QWidget{ Q_OBJECTpublic: QThread * thread; //
2020-07-25 21:07:23
1547
原创 Linux C语言 生产者消费者模型 条件变量互斥锁实现
生产者消费者模型程序实现#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>typedef struct MSG{ struct MSG* next; struct MSG* pre; int id;}msg_t;msg_t *phead = NULL, *ptail = NULL;// 静态初始化 也可以用pt
2020-07-22 21:29:36
934
3
原创 Makefile 规则、变量、函数使用方法总结
文章目录Makefile用法文件命名规则:用途:工作原理:Makefile变量分类:使用Makefile函数函数写法:使用:Makefile用法文件命名规则:Makefile 或者 makefile用途:用于项目的代码编译管理,一次可以编译多个文件,且再次编译时不会对还没有修改过的文件进行重新编译就节省了该文件编译的时间。编写的基本规则:目标文件:生成目标文件所需要的依赖文件 依赖文件生成目标文件的命令例如根据以下文件编写Makefile:makefile文件内容:工作原理:m
2020-07-20 13:46:56
722
原创 IO复用之epoll_*函数介绍
文章目录epoll函数说明epoll_create函数epoll_ctl函数epoll_wait函数回射服务器程序实例epoll函数说明epoll是Unix下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描
2020-07-17 15:43:31
224
原创 IO复用之poll函数介绍
文章目录函数说明编程实现serverclient函数说明函数原型#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);函数功能: 等待一个文件描述符转变为就绪状态参数1:第一个参数是一个结构体类型的数组的首地址struct pollfd { int fd; /* 文件描述符 */ short events; /* 监控的事件 */ short revents; /* 监控事件中满足
2020-07-17 14:39:13
627
原创 IO复用之select函数介绍
文章目录函数说明函数原型:函数功能:参数说明:函数原理编程实现总结描述符就绪条件(拓展)函数说明函数原型:/* According to POSIX.1-2001, POSIX.1-2008 */#include <sys/select.h>/* According to earlier standards */#include <sys/time.h>#include <sys/types.h>#include <unistd.h>in
2020-07-17 13:49:42
462
原创 C语言文件读写操作
文件操作单个字符的输入与读取#define _CRT_SECURE_NO_DEPRECATE#include <stdio.h>#include <stdlib.h>#include <ctype.h>#if 0int main(){ FILE *fp; //定义文件指针 char ch; if ((fp = fopen("D:\\...
2020-07-17 10:45:42
227
原创 Unix下可用的5种I/O模型总结
1. 阻塞式I/O模型最流行的I/O模型是阻塞式IO (blocking I/O)模型,默认情形下,所有套接字都是阻塞的。以数据报套接字作为例子,有下图6-1所示的情形。这里使用UDP而不是TCP作为例子的原因在于就UDP而言,数据准备好读取的概念比较简单:要么整个数据报已经收到,要么还没有。然而对于TCP来说,会导致这个概念变得复杂。在本节的例子中,我们把recvfrom函数视为系统调用,因为我们正在区分应用进程和内核。不论它如何实现,一般都会从在应用进程空间中运行切换到在内核空间中运行,一段时间之
2020-07-17 10:16:05
231
原创 线程控制原语(2) -- 线程回收
pthread_join函数作用:阻塞等待线程退出,获取结束线程的退出状态。其作用相当于进程中 waitpid() 函数。如果没有调用pthread_join函数回收已退出的进程的话,则该进程的退出状态会残留在系统中成为僵尸线程,所以一定要对已经退出的线程进程状态回收。#include <pthread.h>int pthread_join(pthread_t thread, void **retval);// Compile and link with -pthread (含有线程的
2020-07-06 19:38:33
184
原创 线程控制原语(1)-- 创建线程
文章目录线程介绍Linux内核线程实现原理线程共享资源线程非共享资源线程优、缺点线程控制原语pthread_self函数pthread_create函数pthread_exit函数创建N个线程总结:线程介绍Linux内核线程实现原理类Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。轻量级进程(light-weight process),也有PCB,创建线程使用的底层函数和进程一样,都是调用同一个内核函数clone。
2020-07-05 22:35:46
457
原创 孤儿进程僵尸进程和回收子进程
孤儿进程孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程就变成init进程,称为init进程领养孤儿进程。 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 int main() 6 { 7 pid_t pid = fork(); 8 if(pid == 0){ 9 while(1) 10
2020-07-05 12:45:16
372
原创 fork()函数介绍和创建多个子进程
fork函数 #include <unistd.h> pid_t fork(void);fork()函数被调用后会立即创建一个子进程,子进程和父进程独立运行互不干扰返回值:在父进程中返回一个大于0的数,表示创建的子进程的id;在子进程中返回 0;-1表示创建失败。创建一个子进程:...
2020-07-04 22:36:37
6404
原创 C/S通信过程和基本socket函数
服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。数据传输的过程:建立连接后,TCP协议提供全双工的通信服务,但是一般的客户端/服务器程序的流程是由客户端主动发起请求,服务器被动处理请求,一问一答的方式。因此,服务器
2020-07-02 19:38:08
1433
原创 03_静态库和动态库的制作和使用
静态库的制作静态库的特点1.命名方式静态库的命名统一为:lib + 静态库名 + .a2. 静态库的优点寻址方便、速度快静态库中会被用到的模块会被一次性打包到可执行程序中发布的可执行程序可直接使用不需要再依赖于静态库3. 静态库的缺点静态库的代码在编译过程中会被载入可执行目标程序中,因此体积较大。如果静态函数库改变了,那么之前发布的程序必须重新编译。4. 使用场景在核心程序上使用,保证速度,可忽视空间,主流应用于80、90年代,现在很少用制作过程1. 创建存储文件夹:
2020-06-29 23:50:45
776
2
原创 02_可执行文件生成过程和gcc参数介绍
文章结构可执行文件生成过程1.预处理器2.编译器3.汇编器4.链接器gcc参数用法语法参数可执行文件生成过程对于一个源文件test.c生成可执行文件test.out的过程如下:1.预处理器输入文件:test.c执行命令:gcc -E test.c -o test.i功能:展开头文件、去掉注释、宏替换输出文件:test.i2.编译器输入文件:test.i执行命令:gcc -S test.i -o test.s...
2020-06-28 19:14:59
604
原创 01_vim的常用命令及模式切换
目录三个模式的切换方式命令模式命令文本模式命令末行模式命令三个模式的切换方式命令模式命令vim进入文件是的模式:vim +文件名保存并退出:ZZ分类 命令 作用 说明 移动光标 h、l、j、k 对应上、下、左、右 gg 光标移动文件开头 G 光标移动到文件末尾 0 光标移动到行首 $ 光标移动到行尾 123G 跳转到第123行 删除 x 删除光标后一个字符...
2020-06-28 15:28:24
305
原创 LeetCode 打家劫舍系列问题 (练DP很好的例子)
打家劫舍I(动态规划)打家劫舍II(动态规划)打家劫舍III(树型DP)打家劫舍I(动态规划) 状态表示:dp[i][0/1]表示第i个房子偷或不偷的最高金额 初始边界:dp[0][] = {0,0} 转移方程: 当前房子不偷:dp[i][1] = dp[i-1][0] + nums[i] 当前房子偷: dp[i][0] = max{dp[i-1][0],dp[i-1][1]} int rob(vector<int>&.
2020-06-04 15:20:39
382
原创 LeetCode 421.数组中两个数的最大异或值 (前缀树+位运算+贪心)
题目描述思路总的来说就只需要两步:将数组中的数全部存入字典树中遍历树中的每一个数在字典树中异或的最大结果,最后再求最大结果里面的最大值返回也可以将1、2两步写在一个循环里面,也可以分开写,时间复杂度都是一样的class Trie{public: Trie* next[2]; Trie() { memset(next, 0, sizeof(next)); }};class Solution { Trie* root = new T
2020-06-03 14:52:13
324
原创 LeetCode 96.不同的二叉搜索树(卡特兰数列)
题目描述记忆化搜索对于每个节点而言都可以在区间1到n中取一个数作为根节点,比如这里取i,则左子树能在根节点1 – i - 1中取值作为根节点,右子树能在i + 1 – n中取值作为根节点。最后当前节点能取的可能就是左右子树能取可能情况的乘积。对于子树节点我们可以以同样的方式递归地去求。由于这样会有很多重复的计算,所以我们用一个map来记录已经计算过的结果,避免重复计算,这就是记忆化搜索。 unordered_map<string,int> mp; int numTrees
2020-06-01 15:39:04
245
原创 kruskal和prim算法如何实现最小生成树
kruskal和prim算法是用来求最小生成树的算法,那什么是最小生成树呢?最小生成树是一副连通加权无向图中一棵权值最小的生成树,也就是图中包含全部节点且权值和最小的连通子图。kruskal和prim算法讲解对于kruskal和prim算法的讲解这里有个秒懂视频,讲解的很详细,可以参考下。kruskal和prim算法秒懂视频kruskal算法实现步骤:将图中的所有边取出并且按权值由小到大排序将已排好序的边从小到大依次还原,若还原的过程中出现环,则舍弃该边重复步骤2直到选出N-1条边为止
2020-05-31 10:12:12
377
原创 抽象工厂学习总结(全面)
工厂模式介绍工厂模式分为简单工厂模式、工厂方法模式 和 抽象工厂模式三类简单工厂 VS 工厂方法这里通过实现一个计算器例子来了解简单工厂和工厂方法模式简单工厂模式的计算器实现#include <iostream>using namespace std;class CalBase{public: double num1; double num2;public: virtual double cal() = 0;};class Add : public CalBas
2020-05-23 13:24:05
1055
原创 模板方法模式学习总结
模板方法模式介绍模板方法模式定义:定义一个操作中的算法的骨架,而将一些多变的步骤延迟到子类中实现,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。解释:对于一个类,把类中多变的部分和不变的部分分离开来,将多变的部分延迟到子类去实现,不变的部分封装在基类中。优点:封装不变部分,扩展可变部分。提取公共代码,便于维护。行为由父类控制,子类实现。缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。使用场景:对于base class 有
2020-05-21 22:45:45
377
原创 策略模式实现和总结
策略模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
2020-05-20 15:56:37
465
原创 LeetCode 1371签到题 每个元音包含偶数次的最长子字符串 (位运算)
题目描述提示:1 <= s.length <= 5 x 10^5s 只包含小写英文字母。思路描述:首先题目中要求子字符串中每个元音字母恰好出现偶数次,我们就可以使用0和 1 来标识每个字母的状态(偶数次或奇数次),我们不需要知道每个字母出现的完整次数,只需要知道这个次数的奇偶性那么我们可以注意到奇数次+ 1 = 偶数次,偶数次 + 1 = 奇数次,所以我们可以使用 异或 来参与运算: 比如 aba初始时 status = 00000,然后到 a的时候00000 ^ 00001
2020-05-20 12:16:24
296
原创 代理模式学习总结
代理模式定义代理模式的定义: 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。代理模式的优点:代理模式在客户端与目标对象之间起到一个中介和保护目标对象的作用;代理对象可以扩展目标对象的功能;代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;代理模式的缺点:在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;增加了系统的复杂度;代理模式的结
2020-05-19 18:23:13
307
原创 面试经常被问的单例模式到底长啥样
饿汉式和懒汉式单例模式书中的官方定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问节点。解释:就是一个类除了实例化一个对象之外保证没有其他实例化可以被创建,并且它可以提供一个访问该实例的方法。所以我们可以明确知道单例模式就是一个类,但这个类有点特殊,特殊在他只能创建一个实例,而对外就是提供一个外界可以访问的实例化方法。但是我们如何保证让它只能实例化一个对象呢?可以看看下面这样一个代码。// 懒汉式class Single{private: Single() { } //
2020-05-18 18:28:11
307
原创 LeetCode 10正则表达式匹配 (动态规划)
题目描述回溯老样子,写不出来动态规划先写暴力递归:如果没有星号(正则表达式中的 * ),问题会很简单——我们只需要从左到右检查匹配串 s 是否能匹配模式串 p 的每一个字符。当模式串中有星号时,我们需要检查匹配串 s 中的不同后缀,以判断它们是否能匹配模式串剩余的部分。一个直观的解法就是用回溯的方法来体现这种关系如果模式串中有星号,它会出现在第二个位置,即 pattern[1]。这种情况下,我们可以直接忽略模式串中这一部分,或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即pat
2020-05-18 15:58:50
360
原创 LeetCode 4.寻找两个正序数组的中位数 (二分查找)
题目描述解法一:申请两个堆,分别为大顶堆和小顶堆,可以用优先队列实现。维护这两个堆,使得大顶堆里面的元素都小于小顶堆里面的元素,同时大顶堆里面元素的个数与小顶堆里面的元素个数相差不能超过1。将数组里面的数都装入堆中后,则中位数就是两个堆的堆顶元素如果两个数组的元素之和为奇数的话就是堆中元素个数较多的堆顶元素。如果两个数组元素之和为偶数的话就是堆顶 元素的平均值。 void pushNum(priority_queue<int,vector<int>,grea
2020-05-18 10:47:13
242
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人