【发布时间】:2010-07-09 09:42:31
【问题描述】:
我正在研究的一些 C++ 库具有一个简单的跟踪机制,可以激活该机制以生成日志文件,显示调用了哪些函数以及传递了哪些参数。它基本上可以归结为TRACE 宏被溢出到整个库的源代码中,并且宏扩展为如下内容:
typedef void(*TraceProc)( const char *msg );
/* Sets 'callback' to point to the trace procedure which actually prints the given
* message to some output channel, or to a null trace procedure which is a no-op when
* case the given source file/line position was disabled by the client.
*
* This function also registers the callback pointer in an internal data structure
* and resets it to zero in case the filtering configuration changed since the last
* invocation of updateTraceCallback.
*/
void updateTraceCallback( TraceProc *callback, const char *file, unsinged int lineno );
#define TRACE(msg) \
{ \
static TraceProc traceCallback = 0; \
if ( !traceCallback ) \
updateTraceCallback( &traceCallback, __FILE__, __LINE__ ); \
traceCallback( msg ); \
}
这个想法是人们可以在他们的代码中只说TRACE("foo hit"),这样要么
调用调试打印函数,否则它将是空操作。他们可以使用其他一些 API(此处未显示)来配置仅应打印位置(源文件/行号)中使用的 TRACE。此配置可以在运行时更改。
这个问题是现在应该在多线程代码库中使用这个想法。因此,TRACE 扩展为的代码需要在面对同时运行代码的多个执行线程时正常工作。现在代码库中大约有 20.000 个不同的跟踪点,而且它们经常被命中,所以它们应该是相当高效的
使这种方法线程安全的最有效方法是什么?我需要适用于 Windows(XP 和更新版本)和 Linux 的解决方案。我担心只是为了检查过滤器配置是否更改而进行过度锁定(99% 的时间跟踪点被命中,配置没有更改)。我也愿意对宏进行更大的更改。因此,与其讨论互斥锁与临界区的性能,不如说宏只是将事件发送到不同线程中的事件循环(假设访问事件循环是线程安全的)并且所有处理都发生在同一个线程中,这也是可以接受的线程,所以它使用事件循环同步。
更新:我大概可以把这个问题简化为:
如果我有一个线程读取指针,而另一个线程可能写入变量(但 99% 的情况下不会),我如何避免读取线程需要一直锁定?
【问题讨论】:
-
错字。 “updateTraceBallback”而不是“updateTraceCallback”。
-
@SigTerm:谢谢,已修复。
-
如果配置可以在运行时改变,为什么不把它转换成一个宏,只做一个正常的方法调用,内部检查那个标志?
-
@Lasse:我当然可以这样做,但这并没有多大帮助:对函数查询的标志的访问需要同步,并且在 99% 的情况下标志没有'不要改变所以同步成本被浪费了。我想避免在这里同步(或让它变得非常便宜)。
标签: c++ multithreading logging trace