“有两种编写无错误程序的方法;只有第三种有效。” -艾伦·J·佩利斯

在关键计算机应用程序的生命周期中,日志记录是非常重要的活动,尤其是在故障症状不明显时。 日志记录提供了故障之前应用程序状态的最大详细信息,例如变量的值,函数的返回值等。 在一段时间内会生成单调增加的跟踪数据,并将其连续写入磁盘上的文本文件中。 有效的日志记录需要大量磁盘空间,并且在多线程环境中(其中有多个线程写入其跟踪信息)会增加很多倍。

常规文件记录的两​​个主要问题是:硬盘上的空间可用性以及在将数据写入文件时磁盘I / O缓慢。 连续写入磁盘会大大降低程序的性能,导致其运行缓慢。 通常,空间问题是通过使用日志轮换策略解决的,该日志策略将日志保存在多个文件中,这些文件在达到一定数量的预定义字节时会被截断并覆盖。

为了克服空间问题并最大程度地减少磁盘I / O,某些程序将其跟踪数据记录在内存中,仅在需要时将其转储。 这种循环的内存中缓冲区称为环形缓冲区 。 本文讨论了环形缓冲区的常见实现,并提出了一些在多线程程序中启用环形缓冲区机制的想法。

环形缓冲区

环形缓冲区是一种用于应用程序的日志记录技术,通过该技术,将要记录的相关数据保留在内存中,而不是每次将其写入磁盘上的文件中。 可以在需要时将内存中的此数据转储到磁盘,例如,当用户请求将文件中的内存数据转储,程序检测到错误或由于非法操作或收到信号而导致程序崩溃时。 环形缓冲区日志记录由固定大小的已分配内存缓冲区组成,供进程进行日志记录。 顾名思义,缓冲区以循环方式实现。 当缓冲区填充数据时,它不会在开始时再次写入,而不是为新数据分配更多的内存,从而覆盖了先前的内容。 有关示例,请参见图1 。

图1.写入环形缓冲区

图1显示了将两个日志条目写入环形缓冲区时的状态。 写入第一个日志条目(以蓝色显示)后,当进程尝试写入第二个日志条目(以红色显示)时,缓冲区中没有足够的空间。 该进程将写入所有可能的数据,直到缓冲区结束为止,其余的数据将被复制以开始覆盖先前的日志条目。

请参阅相关的主题为环形缓冲区实现的示例。

从环形缓冲区读取是通过保留读取指针来完成的。 该指针和写指针会相应移动,以确保读指针在读取时永远不会越过写指针。 为了提高效率,某些应用程序保留原始数据,而不是将格式化的数据放入缓冲区。 在这种情况下,需要一个解析器,该解析器从那些内存转储中生成有意义的日志消息。

环形缓冲区的优点

当您可以简单地写入文件时,为什么还要使用环形缓冲区? 由于您要覆盖环形缓冲区中的先前内容,因此会丢失数据。 与传统的文件日志记录机制相比,环形缓冲区具有以下优点。

  • 很快 写入内存比对磁盘进行I / O快得多。 仅在需要时才执行刷新数据。
  • 连续日志记录可能会占用系统上的空间,从而导致其他程序也用完空间并失败。 在这种情况下,要么必须手动删除日志,要么必须实施日志轮换策略。
  • 启用日志记录后,无论是否需要,该过程都会继续填满硬盘上的空间。
  • 有时,您只需要在程序崩溃之前获取数据,而不是进程的完整历史记录即可。
  • 在多线程应用程序的情况下,用于调试的常用功能(如printf,write等)有时会更改程序的行为,从而使其难以调试。 使用这些功能可能导致应用程序无法发现某些否则会引起注意的错误。 这些函数是取消点,可能会导致在程序不期望的情况下在线程环境中传递挂起的信号。 下面的清单1和清单2中的假设示例(伪代码)使其更加清晰。
清单1.未启用调试的代码
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
/* I should not be cancelled in the below section */
var=5;
#ifdef DEBUGwrite(fd,"Value of var = 5\n",17);
#endif
var=pow(var,2);/* I can be cancelled now */
pthread_testcancel();
清单2.启用调试的代码
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
/* I should not be cancelled in the below section */
var=5;
#ifdef DEBUG
write(fd,"Value of var = 5\n",17);  <======== Cancel delivered here!
#endif
var=pow(var,2);/* I can be cancelled now */
pthread_testcancel();

在多线程程序中使用环形缓冲区

有时,当其他传统的日志记录方法失败时,环形缓冲区日志记录可以解决。 本节讨论使用环形缓冲区启用在多线程应用程序中的日志记录时要考虑的一些重要点。

同步一直是访问公共资源时多线程程序必不可少的部分,并且日志记录也不例外。 当每个线程尝试写入全局空间时,必须注意它们同步写入内存,否则消息将被破坏。 通常,每个线程在写入缓冲区之前会先获取一个锁,该缓冲区在完成时释放。 您可以下载使用锁写入内存的环形缓冲区的示例。

这种方法有一个缺点:如果您的应用程序有多个线程,并且每个线程都在详细级别上进行日志记录,则该过程的整体性能会受到影响,因为线程大部分时间都花在了获取和释放锁上。

通过使每个线程写入其自己的内存块,可以完全避免同步问题。 当用户发出转储数据请求时,每个线程都会获取一个锁并将其转储到中央位置。 由于仅在将数据刷新到磁盘时才获得锁定,因此性能不会受到很大影响。 在这种情况下,您可能需要一个附加程序来按时间顺序对线程ID或时间戳上的日志信息进行排序,以对其进行分析。 您也可以选择只写消息代码,而不是将完整格式的消息写到内存中,然后通过使用外部实用程序解析转储,将其转换为有意义的文本。

避免同步问题的另一种方法是分配大块全局内存并将其分成较小的插槽,每个线程将在其中使用一个插槽进行日志记录。 每个线程只能读写自己的插槽,而不能读写整个缓冲区。 当每个线程第一次尝试写入数据时,它都会尝试查找内存的空插槽并将其标记为忙。 当线程获取特定的插槽时,可以使用设置为1的位图来跟踪插槽的使用情况,并在线程退出时将其重新设置为0 。 维护当前使用的插槽号的全局列表,以及使用该插槽号的线程的线程信息。

为了避免线程死亡而没有将插槽的位图重置为0 ,您需要一个垃圾回收器线程,该线程将遍历全局列表并基于线程ID以固定间隔轮询该线程。 它释放插槽并修改全局列表。 有关示例,请参见下面的清单3 。

清单3.垃圾收集器线程的样本伪代码
void Check_and_free(List *ptr){int slotno,ret_val;LockList();while(ptr){if ( ((ret_val = pthread_kill(ptr->thread_id,0)) == ESRCH) ){/* Thread has died */slotno=ptr->slotno;Free_slot(ptr->thread_id);Mark_bitmap_free(slotno);}ptr=ptr->next;}UnlockList();return ;
}

线程ID经常被重用,因此在某些情况下,线程可能会死而没有释放插槽,并在垃圾回收器释放它之前出现并分配了一个新的插槽。 对于新线程而言,检查全局列表并重用同一插槽(如果先前实例已使用该插槽)非常重要。 由于垃圾收集器线程和编写器线程都可以尝试同时修改全局列表,因此还必须使用某种锁定机制。

当用户发出转储环形缓冲区数据的信号时,处理该信号的线程将停止其他线程更改缓冲区的内容,并将已使用的插槽的内容转储到文件中。 清单4和清单5显示了将数据写入环形缓冲区并将其内容转储到文件的示例。 一旦接收到信号以转储数据, is_dumping全局变量将用于阻止其他线程更改缓冲区的内容。

清单4.用于写入环形缓冲区的插槽“ i”的示例伪代码
void Write_to_buffer(char *msg){read_atomically(&is_dumping);if(!is_dumping)memcpy(slot[i]->ptr,msg,strlen(msg));return;
}
清单5.转储环形缓冲区数据的示例伪代码
void Dump_data(int fd){change_atomically_to_true(&is_dumping);for i in each_used_slot {write_slot_data_to_file(fd,slot[i]);}change_atomically_to_false(&is_dumping);return;
}

结论

环形缓冲区通过使用内存操作代替文件操作来提高日志记录的效率。 为缓冲区选择适当的大小可确保转储相关消息,这在对程序进行事后分析时会有所帮助。 环形缓冲区是连续记录程序的理想解决方案,调试时不需要完整的程序历史记录。 本文讨论了在多线程程序中实现环形缓冲区时的一些方法和注意事项。


翻译自: https://www.ibm.com/developerworks/aix/library/au-buffer/index.html

多线程 环形缓冲区_使用环形缓冲区有效登录多线程应用程序相关推荐

  1. python多线程怎么写_怎么样优雅的使用python多线程?python进阶

    Python多线程类似于同时执行多个不同程序,但其执行过程中和进程还是有区别的,每个独立的线程有一个程序运行的入口.顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提 ...

  2. java 文件缓冲区_基于直接缓冲区和非直接缓冲区的javaIO文件操作

    基本概念: 1. 非直接缓冲区:  指的是通过jvm来缓存数据的,应用程序要读取本地数据要经历从本地磁盘到物理内存,然后copy到jvm中,然后再通过流的方式读取到应用程序中,写的操作正好与之相反. ...

  3. java环形队列_使用环形队列触发延时任务

    类似需求:"如果连续30s没有请求包(例如登录,消息,keepalive包),服务端就要将这个用户的状态置为离线". 轮询处理 将所有任务都添加到某集合中,定时轮询扫描,如果达到条 ...

  4. c 多线程运行混乱_一篇文章读懂 Python 多线程

    本文作者为 Michael Driscoll,是其新书 Python 201 的一节.本文译者为 linkcheng,由EarlGrey@编程派校对. 译者简介:linkcheng,专业电子信息工程. ...

  5. 多线程面试题_线程,代码和数据–多线程Java程序实际运行的方式

    多线程面试题 有些事情是您在学术或培训班上没有学到的,经过几年的工作经验后才逐渐了解,然后您才意识到,这是我最想念的那几年,这是非常基本的. 了解多线程Java程序的执行方式就是其中之一. 您肯定已经 ...

  6. 单片机实现环形队列_单片机模块化程序: 难道有环形队列串口发送数据就万事大吉了吗...

    1.问个问题,下面程序有没有BUG数组 2.环形队列虽然解决了一开始的中断发送数据覆盖问题,可是呢却引入了新的问题函数 3.而后看看中断发送测试 4.想没想明白是什么问题spa 5.发送数据1 和发送 ...

  7. c++清空输入缓冲区_干货 | C++的输入输出方法

    C和C++并没有将输入与输出实现在语言中,而是在类库中实现.作为C的超集,C++继承了C的输入输出方法.同时将输入与输出视为字流.流充当了程序和流源流目标之间的桥梁.本文将介绍C++的输入输出方式,并 ...

  8. 单片机实现环形队列_稀疏数组和队列(二)

    队列的介绍 队列以一种先入先出(FIFO)的线性表,还有一种先入后出的线性表(FILO)叫做栈. 教科书上有明确的定义与描述.类似于现实中排队时的队列(队尾进,队头出),队列只在线性表两端进行操作,插 ...

  9. python画环形图_用Python把图做的好看点:用Matplotlib画个环形图

    P老板:小Lo啊,你觉得这几个图好看吗 我:好看,好看 P老板:我也觉得,这个月的月报,就用这个把,你给我几个,我看看 我:..... 于是乎,我们今天的目标是什么!!! 画个环形图!!! 今天,我们 ...

最新文章

  1. Leangoo看板协作工具“免费版”和“企业版”差异
  2. python详细安装教程3.7.0-python 3.7.0 安装配置方法图文教程
  3. css匹配title,解决css中的匹配问题
  4. java清除输出内容_java – 从JSch中的命令输出中删除shell东西...
  5. springboot + redis
  6. 编写junit 测试_使用JUnit和Repeat注​​释编写有效的负载测试
  7. 【转】关于字符编码,你所需要知道的
  8. 【视频教程】捷微开发视频系统讲课-陆续更新
  9. vue 和react
  10. 数学归纳法证明时间复杂度
  11. abbex 区块链学院如何交易之 第十五章 应对意外
  12. 基于web版kettle开发的用户专业版B/S架构工具
  13. 修炼你的《九阳神功》行走江湖
  14. 将应用程序设置可信任(在win10操作系统)
  15. 虚拟化堆叠技术-典型配置H3C IRF
  16. python和excel相关的是什么知识点_Python 与 Excel 不得不说的事
  17. Android Preference详解
  18. 数字信号处理 --- 用离散傅里叶变换(循环卷积)实现线性卷积(个人学习笔记)
  19. Swift 调用C++代码
  20. JDK1.8新特性Lambda表达式入门

热门文章

  1. 消息总线扩展之面向消息的数据集成
  2. 【转载】入坑KeePass(七)Keepass 2.x 之 同步与触发器
  3. Games104 Lecture 12 游戏引擎中的粒子和声效系统
  4. 六、图(上):六度空间
  5. 记录一下StamPS+SBAS的过程
  6. 单片机断电记忆方法C语言,怎样使单片机程序断电保留上次的数据?
  7. 手把手教你做Android聊天机器人
  8. 计算机课教案评语,信息技术教学的关键环节之三:教学评价
  9. 比win7运行快的linux发行版,旧电脑扔了浪费!装SliTaz系统,瞬间运行流畅如新机,比win7更快...
  10. 微博图片地址查uid网页版源码