一、相关时间函数 1. gettimeofday() 2. time() 3. clock() 二、间隔定时器 1. setitimerval() 2. getitimerval() 3. 实时定时器的使用 三、为阻塞操作设置超时 1. alarm() 2. 给read()设置读超时 一、相关时间函数 1. gettimeofday() 获取日历时间。 #include <sys/time.h> int gettimeofday(struct timeval *tv, struct timezone *tz); timeval结构体 struct timeval { time_t tv_sec; // 秒 suseconds_t tv_usec; // 微秒(long int) }; 2. time() 返回自Epoch(格林威治标准时间1970.01.01 0:00 继续阅读 >>


王良 18/08/23 09:43:00
一、被中断的系统调用(EINTR)的理解 1. 慢系统调用是? 2. 慢系统调用的类别 3. EINTR产生的原因 5. 一般处理方法 二、SIGCHLD信号的处理 1. SIGCHLD信号的产生 2. SIGCHLD信号的处理 3. 不处理SIGCHLD的后果 三、示例代码 一、被中断的系统调用(EINTR)的理解 1. 慢系统调用是? 慢系统调用指可能永远阻塞的系统调用。 也就是处于阻塞状态的系统调用,如果不收到需要的信息,就会一直阻塞在那里。例如accept:在服务器等待客户端建立连接时,如果没有客户端来请求连接,那么accept就会一直阻塞,直到有客户端请求连接为止。像这种系统调用,就称为慢系统调用。 2. 慢系统调用的类别 对管道的读写 对终端设备设备的读写 对网络连接的读写 …… 值得注意的是,读写磁盘文件一般不会阻塞,一般会返回给调用者(在没有硬件故障的条件下) 3. EINTR产生的原因 当阻 继续阅读 >>


王良 18/08/20 15:11:16
三次握手与四次挥手 通过TCP/IP协议的学习,我们可以知道TCP协议是一种面向连接的、可靠的传输协议。其中,为了保证客户端与服务器连接的有效性,就有了本篇文章所要介绍的“三次挥手”;而“四次挥手”则是为了保证连接的正确断开。 1. TCP状态 首先,介绍一下TCP的几个状态: SYN —— 同步序列编号,在建立连接时发送 ACK —— 确认信息,在确认SYN信息时发送,响应信息 FIN —— 关闭连接 RST —— 连接重置 PSH —— 有数据传输 URG —— 紧急指针字段值有效 2. 三次握手 建立TCP连接时会经过如下步骤: 服务器准备接收客户端连接(通过socket API),由于连接是由客户端激发的,因此称为被动打开 客户端调用connect开始主动打开,并发送SYN(syn = i)包,告诉服务器发送数据的序列号 服务器确认(ACK,ack = i+1)客户端发来的信息(SYN),并发送SYN(syn = j),其中含有服务器发送数据的初始序列号。注:SY 继续阅读 >>


王良 18/08/15 08:58:10
生产者消费者模型 生产者消费者模型 一、 生产者消费者问题 二、 问题分析 三、 伪代码实现 四、代码实现(C++) 五、 互斥锁与条件变量的使用比较 一、 生产者消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。 . 要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等 继续阅读 >>


王良 18/08/11 00:43:20
最小堆及其应用:时间堆 最小堆及其应用:时间堆 一、 堆 1. 概念 2. 最小堆的实现 3. 性质 4. 代码 二、时间堆 1. 概念简述 2. 实现细节 3. 代码 一、 堆 1. 概念 堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左子节点和右子节点的值。 其中,两个叶子节点的大小没有顺序。 堆又分为两种,最大堆、最小堆。由上面的概念我们可以知道: - 最大堆: 任一非叶子节点的值均大于其左子节点和右子节点的值。 - 最小堆: 任一非叶子节点的值均小于其左子节点和右子节点的值。 (图为最小堆) 因此,我们可以得到:最大堆的根节点的值是最大的,最小堆的根节点的值是最小的。所以在需要最值问题的时候,我们可以采用堆这种数据结构来处理。 2. 最小堆的实现 由于堆是一种经过排序的完全二叉树,因此在构建的时候需要对新插入的节点进行一些操作以使其符合堆的性质。这种操作就是节点的上滤与下滤。 继续阅读 >>


王良 18/08/01 17:15:12
还在为在linux下画二叉树等图苦恼吗,现在就安利一波linux程序猿的作图神器——Graphviz。(本来在写其他东西,刚好要绘图,强行插入一篇blog) Graphviz (Graph Visualization Software) 是一个由AT&T实验室启动的开源工具包。DOT是一种图形描述语言,非常简单的,Graphviz就是用来处理这种语言的工具。只需要简单了解一下DOT语言,就可以用Graphviz绘图了,它对程序员特别有用。 官网:http://www.graphviz.org/ 该软件可以使用代码来绘图,可以绘图的种类比较多,可以直接生成png格式的文件。可以画无向图、有向图、二叉树、流程图等等等。 先说简单的感受一下,使用以下代码: graph test { a -- b -- c; b -- d; } 即可生成图片: ubuntu18.04安装Graphviz sudo apt install graphviz 一条命 继续阅读 >>


王良 18/08/01 15:08:26
时间轮 简述 顾名思义,时间轮就像一个轮子,在转动的时候外界会指向轮子不同的区域,该区域就可以被使用。因此只要将不同时间的定时器按照一定的方法散列到时间轮的不同槽(即时间轮划分的区域)之中,就可以实现在运转到某个槽时,进行判断该定时器是否已经到达运行时间(需要判断是由于有的定时器并非在这一圈就需要运行,可能需要后面几圈才会运行。 从图中也可以看出,每个槽中的定时器是以(双向)链表形式存储的,每次添加的时候直接插入到链表的开始(头插法)。值得注意的是,由于使用头插法,因此在运行到某个槽时,需要遍历一遍链表,已检查是否有到达时间的计时器,有的话就运行,并删除结点。 至于在每转到一个槽时都要检查是否到达运行时间,可以这样理解:时间轮进行散列的方法就是取余运算,假设每个槽的间隔为1s,共有n个槽,当前转到了第cur个槽,那么一个定时在 t s以后运行的定时器就要放在第( cur + t % n ) % n个槽,并在运行t / n圈后到达该槽时才会运行。因此一个槽中的定时器运行的时间是相差i( 继续阅读 >>


王良 18/07/31 17:08:21
该webServer使用epoll+threadpool实现,支持GET、POST方法,并添加CGI进行数据计算并返回网页信息,可以解析返回html、picture、mp3、js、css等文件,可以实现稳定的运行。 使用c++编写。 源码请看我的Github。 流程简述 启动服务器,在浏览器输入服务器地址,将向服务器发送HTTP请求 服务器接收数据,新建任务,将任务添加到任务队列 从线程池中唤醒某线程,执行任务。若没有任务线程会处于wait状态;若任务过多,会存储在任务队列中,等待空闲线程来执行 某线程获得任务后,读取浏览器发送的请求信息,进行解析HTTP首部,根据对应的结果来进行相应的处理,返回信息,若文件不存在则返回404.html,若请求方法不存在则返回501错误信息。 若是POST,则需要调用CGI进行处理,并返回相应的信息。 任务结束后,需要进行delete,因为在主进程中,为避免任务未运行完便被析构,需要使用new来新建对象,为避免内存泄露,需要在任务结束后使用delete释放资源 继续阅读 >>


王良 18/07/28 16:45:42
在需要频繁开线程时,创建和销毁线程会话费大量时间,为了提高效率,我们可以在任务开始前,先创建一定数量的线程。这样在接收到任务时,就可以直接使用线程池中处于wait状态的线程,在任务结束后线程回到wait状态,等待新任务的到来,这就避免了线程的创建与销毁,从而提高程序执行效率。 所需数据 需要存储有多少线程( int thread_number ) 需要开辟对应的数组,存储线程号( pthread_t *threads ) 需要一个任务队列来存储未执行的任务,便于线程竞争任务并执行( task_queue ) 需要一个flag来标记线程池是否结束,该标记可以在线程池结束后唤醒所有处于等待线程的线程,让它们可以正常退出(其中,所有线程处于脱离(detach)状态) 互斥锁与条件变量,用于避免在获取与添加任务时发生错误(同步与互斥) 运行流程 执行ThreadPool的构造函数,初始化有关数据,进行线程的创建,并将线程进行脱离(使线程在运行完后可以自动回收) 创建的线程会去执行工作线程, 继续阅读 >>


王良 18/07/28 10:35:57
再次重装了系统,为方便以后再次重装,,,因此将主要步骤记录下来。 1. 更新源 sudo gedit /etc/apt/sources.list # 阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb http://mirrors.aliy 继续阅读 >>


王良 18/07/23 13:16:22