自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(42)
  • 收藏
  • 关注

原创 类的几点设计原则

1.即使是一个抽象基类,如果它有非静态数据成员,也应该给它提供一个带参数的构造函数,来初始化它的数据成员。或许你可以通过其派生类来初始化它的数据成员(假如nostatic data member为publish或protected),但这样做的后果则是破坏了数据的封装性,使类的维护和修改更加困难。由此引申,类的data member应当被初始化,且只在其构造函数或其member function中...

2019-07-05 17:35:07 214

原创 成员初始化列表

什么时候使用初始化列表在构造函数中对于对象成员的初始化发生在初始化队列中——或者我们可以把初始化队列直接看做是对成员的定义,而构造函数体中进行的则是赋值操作。所以不难理解有四种情况必须用到初始化列表:当初始化一个引用成员的时候当初始化一个const成员的时候成员对象没有默认构造函数基类对象没有默认构造函数前两者因为要求定义时初始化,所以必须明确的在初始化队列中给它们提供初值。后两者...

2019-07-03 21:07:00 287

原创 锁的实现机制

在多线程编程中,为了保证数据操作的一致性,操作系统引入了锁机制,用于保证临界区代码的安全。通过锁机制,能够保证在多核多线程环境中,在某一个时间点上,只能有一个线程进入临界区代码,从而保证临界区中操作数据的一致性。所谓的锁,说白了就是内存中的一个整型数,拥有两种状态:空闲状态和上锁状态。加锁时,判断锁是否空闲,如果空闲,修改为上锁状态,返回成功;如果已经上锁,则返回失败。解锁时,则把锁状态修改为空...

2019-07-03 17:21:23 715 1

原创 计算机网络之HTTP协议

HTTP协议的组成1、常用的HTTP方法有哪些?**GET: **用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器。**POST:**用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。**PUT: **传输文件,报文主体中包含文件内容,保存到对应URI位置。**HEAD: **获得报文首部,与GET方法类似,只是不返回报文主体,一...

2019-07-03 14:28:10 209

原创 拷贝构造函数

我们通常认为当一个类为没有定义拷贝构造函数的时候,编译器会为其合成一个,答案是错误的。编译器只有在必要的时候在合成拷贝构造函数。那么编译器什么时候合成,什么时候不合成,合成的拷贝构造函数在不同情况下分别如何工作呢,这是本文的重点。什么时候调用拷贝构造函数显式地将一个类的对象作为另一个对象的初值将实参对象传递给实参对象的时候函数返回一个对象的时候其中后面两个会生成临时对象。编译器何时...

2019-07-03 09:04:33 155

原创 深入理解构造函数

我们通常认为:没有定义默认构造函数的类都会被编译器生成一个默认构造函数。编译器生成的默认构造函数会明确初始化类中每一个数据成员。但其实并不是这样。C++ Annoted Reference Manual告诉我们default constructor…在需要的时候被编译器产生出来,那么问题来了,什么时候是需要的时候?C++标准规定:如果类的设计者并未为类定义任何构造函数,那么会有一个默...

2019-07-02 20:36:23 138

原创 malloc实现过程

前言最近重温深入理解计算机系统,看到了malloc的实现,malloc主要涉及到两个系统调用brk和mmap.废话不多说直接上源码,一切尽在源码之中。brk系统调用的入口函数为sys_brk()sys_brk系统调用源码SYSCALL_DEFINE1(brk, unsigned long, brk){ unsigned long retval; unsigned long...

2019-07-01 14:39:10 594

原创 LeetCode 99 恢复二叉搜索树

题目:二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。示例 1:输入: [1,3,null,null,2] 1 / 3 \ 2输出: [3,1,null,null,2] 3 / 1 \ 2解题思路方法一:最简单也是最暴力的方法,我们看到二叉搜索树,第一反应就应该知道要用中序遍历,于是我们对这棵树进行中序遍...

2019-06-22 10:06:05 142

原创 muduo如何解决busy-loop

当连接达到文件描述符的上限,此时没有可供你保存新连接套接字的文件描述符了,那么新来的连接就会一直放在accept队列中,于是呼应其可读事件就会一直触发读事件(因为你一直不读,也没办法读走它),这就是我们常常说的busy-loop.如何解决Busy-Loop//Acceptor构造函数Acceptor::Acceptor(EventLoop* loop, const InetAddress&a...

2019-06-03 19:47:44 943

原创 深入剖析struct与class

谈到struct和class的区别,我们的第一反应就是struct也可以和class一样拥有多态,继承的特性,最大的不同只是他们的默认权限不同,struct默认访问权限是public,class默认权限是private,但其实还有一点:memory layout可能不同。struct(没有使用虚函数)的数据成员声明顺序和这些数据成员在内存中的offset一定是一致的。而class只有在POD原则...

2019-06-02 10:29:07 238

原创 STL源码剖析之空间配置器

1.空间分配器的标准接口通常,C++内存分配和释放的操作如下:class Foo {...};Foo *pf = new Foo;delete pf;new内含2阶段操作:调用::operator new分配内存调用构造函数构造对象delete也含2阶段操作:调用析构函数析构对象调用::operator delete释放内存STL allocator将new...

2019-06-01 13:04:31 186

原创 队列

队列队列是常见的数据结构之一,队列是“操作受限”的线性表,具有先进先出的特性,在STL中,queue可以通过封装deque来实现,同时也可以通过list来实现,一般来说链表的实现可以分为顺序队列,链式队列和循环队列顺序队列要点入队时,当末尾指针tail到达数组容量时,且头指针head != 0,表示数组中还有空间,可以进行数据搬移,否则表示队列满了出队时要进行判空操作代码实现#i...

2019-05-30 12:27:24 90

原创 组合与聚合

类与类之间的三种主要关系Inheritance 继承关系Composition 组合关系Delegation 聚合关系组合**定义:has-a关系,一个类中有包含另一个类,****是包含一个对象,不是包含一个指针。**如何你组合了这个类,那么你将拥有这个类的全部功能1.实例#include<deque>#include <queue>template ...

2019-05-27 17:35:19 2724 1

原创 半同步半异步进程池的实现

进程池的基本思想由主进程管理所有监听socket,而各个子进程分别管理属于自己的连接的socket,子进程可以自己调用accept来接受新连接,这样父进程就无需向子进程传递socket,而只需要简单的说一声."我检测到了有新的连接,你来接受一下“进程池的代码逻辑每个进程类都有一个m_pid用来标识自己,还有一个管道成员来统一信号源,处理信号事件进程池类使用单例模式创建,其构造函数为pri...

2019-05-23 08:43:08 358 3

原创 半同步半异步模式

同步和异步的区别在IO模型中:同步和异步的区分在于内核向应用程序通知的是和种IO事件,同步模式下通知的是就绪事件,异步通知的是完成事件,以及到底是谁来完成I/O读写,同步模式下由应用程序来I/O读写完成,而异步模式下由内核帮我们完成I/O读写。在并发模型中:同步指的是程序完全按照代码的顺序执行;异步指的是程序的执行需要由系统事件来驱动,比如中断,信号等等。同步异步的优缺点按同步方式运行的线...

2019-05-22 17:52:00 641

原创 深入理解CPU上下文切换

CPU上下文切换CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文**。**CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程...

2019-05-21 22:08:28 564

原创 僵尸进程的危害及避免

为什么会存在僵尸进程由于子进程的结束和父进程的运行是一个异步的过程,所以父进程不知道子进程什么时候结束,这可能导致当子进程结束时父进程太忙而丢失子进程结束时的状态信息。于是,UNIX提供了一种机制保证了只要父进程想要看到子进程结束的信息,就能看到。这种机制就是:在每个进程退出时,内核释放所有资源,但扔然保留一定的信息,如进程号,退出信息,运行时间等等,这些信息要知道父进程来取,并且由父进程释放,...

2019-05-21 10:19:27 1043

原创 定时器

前言网络程序一般需要处理的时间有三类:I/O事件,信号事件,定时事件。在上一章我们学习了通过同一事件源对IO事件和信号事件的统一处理,在这章我们将学习对定时事件的统一处理。一般来说我们要将每个定时事件分别封装为定时器,并通过某种数据结构来将所有的定时器串联起来,常见的高性能定时器有时间轮和时间堆。定时方法Linux提供了三种定时方法:socket选项SO_RECVTIMO和SO_SNDT...

2019-05-20 19:13:58 164

原创 信号的统一处理

前言在学习APUE的过程中接触过信号,但往往是对API的了解,以及这些API的简单使用,并没有考虑到其在真实实践中的用法。在系统编程阶段我们可以知道信号是一种异步事件,信号处理函数和主循环是两条不同的执行路线,我们希望信号处理函数能够尽可能快地执行完,以确保信号不会被屏蔽太久。(因为这样可能会引发一些竞态条件),在实际项目中是如何做到的呢。解决一般来说把信号的主要处理逻辑放在主循环,而不是信...

2019-05-18 10:27:20 139

原创 Linux系统编程——信号

基本概念信号的状态产生未决状态 — 没有被处理的递达 — 已经被处理的信号的优先级比较高进程收到信号之后,暂停正在处理的工作信号集不能直接操作阻塞信号集要屏蔽的信号 ---- > 处于未决状态未决信号集没有被处理的信号的集合信号相关的函数kill----发射信号给某个进程函数原型:int kill(pid_t pid,int sig);...

2019-05-18 10:04:12 252

原创 TCP聊天室-简易版

参考于Linux高性能服务器编程,并对代码进行了深度剖析。服务端使用IO多路复用技术实现多个用户连接,主要功能是负责接受客户的数据,并将客户的数据发送给每一个登陆到该服务器上的客户端。服务端代码#include <sys/types.h>#include <arpa/inet.h>#include <netinet/in.h>#include &l...

2019-05-17 11:44:20 318

原创 TCP服务和UDP服务的同时处理

前言在实际的生产环境中,我们的服务程序往往需要同时监听多个端口,从bind系统调用的参数我们知道,一个socket只能与一个socket地址相绑定,即一个socket只能用来监听一个端口。因此要监听多个端口就需要创建多个socket,并将它们分别绑定多个端口,通过IO复用进行监听多个socket.引入通过刚才的介绍我们可以知道,即使是同一个端口,如果服务器要同时监听TCP和UDP请求,则也需...

2019-05-16 14:37:39 1469

原创 非阻塞connnect的使用

前言一般来说,在TCP建立连接的过程中,我们的客户端使用connect发起连接,默认使用的是阻塞模式,只有在有明确结果的时候才会返回(连接成功或连接失败)。这样可能照成当我们向一个“比较远”的服务器发起连接时,我们的程序会阻塞在connect好几秒,这并不是我们想要看到的,如果解决这种问题呢?引入正是由于阻塞connect可能照成上述问题,所以在实际项目中我们一般使用非阻塞connect来解...

2019-05-16 10:48:21 698

原创 EPOLLONESHOT事件

前言即使使用ET模式,一个socket上的同一事件还是可能被触发多次(将TCP缓冲区设置的小一点,发送一个较大的数据,接受的数据会多次填满缓冲区,导致会被触发多次),,当某个线程在读取完某个socket的数据后开始处理这些数据,但在处理这些数据的时候这个socket上又有数据来了,此时另外一个线程被唤醒来读取这些新的数据,于是出现了两个线程同时操作一个socket的局面。但我们期望一个socke...

2019-05-16 09:55:39 406

原创 volatile关键字

volatile提醒编译器它后面所定义的变量随时都可能发生改变,因此编译后的程序每次需要读取这个变量的时候,都会从内存直接读取。如果没有volatile关键字,则编译器可能优化读取和存储,可能展示使用寄存器中的值,如果这个变量由别的程序更新了的话,可能出现不一致现象。一个变量可以既是const又是volatile型的,如只读状态寄存器,是volatile是因为它可能意想不到的被改变,是cons...

2019-05-06 11:28:00 116

原创 Mysql_use_result和Mysql_store_result

**mysql_store_result()**从服务器上检索结果集时,就提取了行,并为之分配内存,存储到客户机中,随后调用 mysql_fetch_row() 就再也不会返回错误,因为它仅仅是把行脱离了已经保留结果集的数据结构。mysql_fetch_row() 返回 NULL 始终表示已经到达结果集的末端。**mysql_use_result()本身不检索任何行,而只是启动一个逐行的检索,就...

2019-05-06 11:24:05 1069

原创 MySQL学习之索引

什么是索引索引的出现是为了提高查询效率,就像书的目录一样,但是实现索引的方式却有很多种,所以这里也就引入了索引模型的概念,可以用于提高读写效率的数据结构很多,这里我先给你介绍三种常见也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。哈希表哈希表的=中的链表并不是有序的,索引哈希索引做区间查询的速度是很慢的,哈希表这种结构适用于只有等值查询的场景有序数组在等值查询和范围查询场景中的...

2019-04-24 20:42:44 122

原创 Linux系统编程——守护进程

守护进程Daemon(精灵)进程,是Linux中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。Linux后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守护进程。如:预读入缓输出机制的实现;ftp服务器;nfs服务器等。创建守护进程,最关键的一步是调用setsid函数创建...

2019-04-24 20:39:40 235

原创 线程同步中的虚假唤醒

在多核处理器下pthread_cond_signal可能唤醒多于一个线程(阻塞在条件变量上的线程)。结果是,当一个线程调用pthread_cond_signal()后,多个调用pthread_cond_wait()或pthread_cond_timedwait()线程返回。这就叫虚假唤醒解决办法:将判断条件改成whilevoid* printA(void *arg){ while(1)...

2019-04-24 20:37:59 203

原创 Linux进程调度

Linux中的进程分为实时进程和普通进程任何实时进程的优先级都要高于普通进程进程可以分为IO消耗型和处理器消耗型IO消耗型大部分时间都用来提交IO请求和等待IO请求处理器耗费型进程把时间都大多用在执行代码上在每个进程的进程控制块中都有一个域policy,用来指明该进程为何种进程,应该使用何种调度策略若PCB中policy为SCHED_NORMAL,则说明该进程为普通进程...

2019-04-24 20:35:46 171

原创 select,poll,epoll区别

什么时候socket可读socket内核中,接受缓冲区的字节数大于等于低水位标志SO_RCVLOWAT,此时调用 recv 或 read 函数可以无阻塞的读该文件描述符, 并且返回值大于0;TCP 连接的对端关闭连接,此时调用 recv 或 read 函数对该 socket 读,则返回 0;侦听 socket ...

2019-04-24 20:33:26 318 1

原创 TIME_WAIT详解

1.time_wait状态是什么简单来说:time_wait状态是四次挥手中服务器向客户端发送FIN终止连接后进入的状态。下图为tcp四次挥手过程可以看到time_wait状态存在于客户端收到服务器Fin并返回ack包时的状态当处于time_wait状态时,我们无法创建新的连接,因为端口被占用。2.为什么会有time_wait状态time_wait存在的原因有两点1.可靠的终止TC...

2019-04-24 20:29:24 5125

原创 mysql学习之唯一索引和普通索引的选择

查询过程假设,执行查询的语句是 select id from T where k=5。这个查询语句在索引树上查找的过程,先是通过 B+ 树从树根开始,按层搜索到叶子节点,也就是图中右下角的这个数据页,然后可以认为数据页内部通过二分法来定位记录。对于普通索引来说,查找到满足条件的第一个记录 (5,500) 后,需要查找下一个记录,直到碰到第一个不满足 k=5 条件的记录。对于唯一索引来...

2019-04-24 12:46:09 340

原创 深入理解快速排序

我们知道快排的核心思想是选取一个基准值,通常我们总是选取最左边的元素作为基准值,并以这个基准值来将数组划为两部分,左边部分为小于基准值,右边部分为小于基准值。但往往我们的数组并不是那么理想的乱序如数组为基本有序的,只有少数元素是有序的此时我们选取最左边的元素作为基准值就可能照成数组的两部分极度不平衡解决办法每次选取基准值时选取一个·随机值数组存在大量的重复元素此时使用...

2019-04-24 11:57:34 111

原创 gdb调试常用命令

使用场景:程序编译无误,但是有逻辑错误。前提条件:可执行程序必须包含调试信息 gcc -cgdb 文件名 —启动gdb调试查看代码的命令:当前文件:list 行号(函数名)指定文件:文件名:行号(函数名)4. 设置断点:当前文件:b 行号(函数名);指定文件:b 文件名:行号(函数名)设置条件断点: b 行号 if 条件查看断点信息:info b删除断点:d 断点的编号...

2018-10-09 22:27:55 175

原创 makefile简明教程.md

makefile的格式目标文件:依赖文件生成目标文件的命令(此行前面必须要有一个缩进!)…执行makefile:make命令命令从下向上依次执行makefile中的自动变量&amp;&lt;:规则中的第一个依赖$@:规则中的目标文件$^:规则中的所有依赖只能在规则的命令中使用&nbsp;main:main.c &nbsp; &nbsp; &nbsp;gcc main.c -...

2018-10-07 22:11:19 429

原创 静态库和动态库的链接制作.md

静态库(编译时就会使用)命名规则lib + 库的名字 + .a;libMytest.a;制作步骤生成.o文件:gcc -c *.c打包.o文件:ar rcs 静态库的名字 *.o使用:gcc main.c -o main -L路径 -l静态库名字或者 gcc main.c -o main 静态库的相径路径空间浪费是静态库的一个问题。另一个问题是静态库对程序的更新、部署...

2018-10-07 22:10:43 229

转载 GCC参数详解.md

简介gcc and g++现在是gnu中最主要和最流行的c &amp; c++编译器 .gcc/g++在执行编译工作的时候,总共需要以下几步:1.预处理,生成.i的文件[预处理器cpp]2.将预处理后的文件不转换成汇编语言,生成文件.s[编译器egcs]3.有汇编变为目标代码(机器代码)生成.o的文件[汇编器as]4.连接目标代码,生成可执行程序[链接器ld]GCC能够处理的后缀有:...

2018-10-06 21:36:48 691

转载 g++报错Core Dump.md

造成这个错误的原因可以能有以下几点 1,内存访问越界:(1)&amp;nbsp;数组访问越界,因为下标出超出了范围。&amp;nbsp;&amp;nbsp;(2) 搜索字符串的时候,通过字符串的结尾符号来判断结束,但是实际上没有这个结束符。(3)使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函数,超出了字符中定义的可以存储的最大范围。使用strncpy, st...

2018-10-06 10:18:32 210

原创 C++Primer读书笔记十——泛型算法.md

概述在前一篇我们介绍了容器的基本概念以及使用其成员函数进行增删改查,但有的时候我们还希望对容器进行更多的操作,比如:查找特定元素,替换元素等。而标准库并未给出此类成员函数,此时需要引入algorithm头文件,其中定义了一系列的操作算法。这些算法不直接操作容器,而是遍历有两个迭代器指定的范围。算法永远不会执行容器的操作泛型算法本身不会执行容器的操作,他们只会运行于迭代器之上,执行迭代器的...

2018-10-01 11:20:07 196

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除