最近写过几个日志类,有一些体会,现在写下来作为笔记,留待以后完善。写一个日志类,目的就是方便将要打印出来的信息,安全的有序的写到指定文件。一般会默认将时间同时写下来,这是在日志写里面处理的。
一个简单地日志,一般一个应用程序只是对应一个log文件。这时出现共享问题,不同的地方使用同一个文件,使用同一个接口写。最开始,我将每一次的日志写都做一次文件的打开,写,关闭。当日志量少的时候,没有涉及到多线程时是可以工作的。但是,有时也会出现问题,毕竟文件是不能共享的,这时,我开始想办法。
1.为了日志的性能,文件的打开关闭只做一次,这是在日志类的构造函数和析构函数中处理。为了有序的写,必须处理同步。这里我想到两个办法,(针对windows环境)。一种是在类中添加静态临界区成员变量,由它来处理同步问题。当然文件句柄也是静态成员变量。这样就可以保证这两个资源在进程中是唯一的,且生命周期足够长。另一种方案是选用系统核心变量,比如事件,互斥体这些。最好是无名的。
当我完成上面这些时,在一个多线程环境下是可以很好的运行的。但是当我将这个类应用到一个多进程环境时,也就是说同一时间可能有多个进程在使用日志文件时,上面方法失败。
经过几天的学习和思考。想到了新的处理办法。就是把日志类的写交给一个守护进程。并且申请一段内存共享区,用来作为进程间的通信。这时遇到几个问题:
1.日志的写写到哪里?
2.写之间的同步?
3.如何保证写数据的不丢失?
4.资源如何合理分配和释放?
解决办法如下:
1.日志的写写到共享区特定区域,
2.同步使用无名事件
3.为了保证数据不丢失,使用写队列
4.资源的分配由日志类完成,释放由守护进程完成
接下来仍然有问题
写队列的设计,不能像普通队列一样随意new和delete,且不能使用指针。这是因为内存共享区映射在不同进程中的地址是不同的,由于是进程间的通信,堆是不能使用的。
解决办法如下,由于堆不能用,普通队列无法使用,标准队列需要重新改写容器接口,鉴于本队列相对简单,我选择自己完成队列,队列中的地址操作改为偏移量(用相对于首地址的偏移量作为地址)。由于内存的特殊,队列的设计是固定在内存区的固定位置,所有的操作免去了new和delete。数据区是否为脏的由自己定义特殊标记。
完成这些以后,将队列作为日志类的成员变量,并将日志类中的其它资源映射到共享类存中的固定位置。这时就完成了日志类在特定内存区的布局。所以日志类的创建需要用 placement new .值得注意的是,在mfc中这种使用new的方法被屏蔽了。解决办法是:屏蔽掉"#define new DEBUG_NEW".完成这些剩下的就很简单了。本文出自 “学习港湾” 博客