http_conn* users = new http_conn[MAX_FD];
因为http_conn对象是MAX_FD个(有限)
所以如果长时间占用,就会浪费。
则使用定时器定时关闭fd。
使用SIGALRM信号实现定时器:alarm(TIMESLOT);
信号处理函数利用管道通知主循环-----
int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd);
每当监测到有这个信号的时候,都会将这个信号写到pipefd[1]里面,传递给主循环。主循环收到信号对升序链表的所有定时器处理-----
如果时间内没有交换数据,就关闭连接。
定时器优化
这个基于升序双向链表实现的定时器存在着其固有缺点:
每次遍历添加和修改定时器的效率偏低(O(n)),使用最小堆结构可以降低时间复杂度降至(O(logn))。
每次以固定的时间间隔触发SIGALRM信号,调用tick函数处理超时连接会造成一定的触发浪费,举个例子,若当前的TIMESLOT=5,即每隔5ms触发一次SIGALRM,跳出循环执行tick函数,这时如果当前即将超时的任务距离现在还有20ms,那么在这个期间,SIGALRM信号被触发了4次,tick函数也被执行了4次,可是在这4次中,前三次触发都是无意义的。对此,我们可以动态的设置TIMESLOT的值,每次将其值设置为当前最先超时的定时器与当前时间的时间差,这样每次调用tick函数,超时时间最小的定时器必然到期,并被处理,然后在从时间堆中取一个最先超时的定时器的时间与当前时间做时间差,更新TIMESLOT的值。
日志系统
日志用到singleton单例模式
:私有化构造函数,防止外部创建。
懒汉模式-饿汉模式
懒汉是第一次被使用才初始化
饿汉则是程序运行时就立刻初始化
条件变量机制
生产者消费者模型
日志运行机制:
日志文件:懒汉模式获取实例,生成日志文件。
同步:格式化输出内容,写入文件
异步:格式化输出内容,写入阻塞队列,创建写进程。阻塞队列取出内容写入日志文件。