c++ - 如何通过非常频繁的读取/非常罕见的写入来同步对全局变量的访问?

标签 c++ c windows multithreading thread-safety

我正在为服务器应用程序调试日志记录基础设施。源代码中的每个日志记录点都在其他参数中指定了它的级别(CRITICAL、ERROR 等)。 所以在源代码中记录点看起来像:

DBG_LOG_HIGH( … )

这是一个扩展为的宏

if ( CURRENT_DEBUG_LOG_LEVEL >= DEBUG_LOG_LEVEL_HIGH ) {
   // prepare and emit log record
}

其中 DEBUG_LOG_LEVEL_HIGH 是一个预定义常量(比方说 2),CURRENT_DEBUG_LOG_LEVEL 是一些表达式,用于评估用户设置的当前调试日志记录级别。 最简单的方法是将 CURRENT_DEBUG_LOG_LEVEL 定义为:

extern int g_current_debug_log_level;
#define CURRENT_DEBUG_LOG_LEVEL (g_current_debug_log_level)

我想允许用户在应用程序执行期间更改当前的调试日志记录级别,并且更改需要几秒钟才能生效。该应用程序是多线程的,对 g_current_debug_log_level 的更改可以轻松序列化(例如通过 CRITICAL_SECTION),但为了不影响性能表达式 ( CURRENT_DEBUG_LOG_LEVEL >= DEBUG_LOG_LEVEL_HIGH ) 应该尽可能快地执行,所以我想避免在那里使用任何线程同步机制。

所以我的问题是:

  1. g_current_debug_log_level 读取中缺少同步会导致读取不正确的值吗?虽然它不应该影响应用程序的正确性,因为用户可能已将当前调试日志记录级别设置为不正确的值,但它可能会影响应用程序性能,因为它可能会导致它在无法控制的时间段内发出非常大量的调试日志。

  2. 我的解决方案能否保证当前调试日志记录级别的更改会在可接受的时间量(比方说几秒钟)后到达所有线程?理想情况下,我希望级别更改操作是同步的,这样当用户收到级别更改操作的确认时,她可以指望根据新级别发出后续日志。

对于满足上述要求的替代实现的任何建议(对级别比较和同步级别更改的性能影响最小,延迟不超过几秒),我也将不胜感激。

最佳答案

没有什么要求在一个内核上的一个线程上进行的写入对另一个内核上的另一个线程读取可见,而不需要提供某种栅栏来在写入和读取之间创建“先于发生”的边缘.

因此,为了严格正确,您需要在写入日志级别之后以及每次读取之前插入适当的内存栅栏/屏障指令。栅栏操作并不便宜,但它们比完全成熟的互斥量便宜。

但在实践中,给定一个在别处使用锁定的并发应用程序,并且如果写入不可见,您的程序将或多或少地继续正确运行的给定事实,写入很可能会偶然变得可见由于在短时间内进行其他围栏操作并满足您的要求。因此,您可能只需编写它并跳过栅栏就可以逃脱。

但是使用适当的围栏来强制执行边缘之前发生的事情确实是正确的答案。 FWIW,C++11 提供了一个明确的内存模型,它定义了语义并在语言级别公开了这些类型的防护操作。但据我所知,还没有编译器实现新的内存模型。因此,对于 C/C++,您需要使用库中的锁或显式防护。

关于c++ - 如何通过非常频繁的读取/非常罕见的写入来同步对全局变量的访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7614755/

相关文章:

C++ - fmod 返回错误答案

c - Qsort 字符串结构

c - 在 C 中的 MPI 中如何创建结构的结构并将其发送到多个进程

linux - 如何在 Archlinux 中启动 NTFS 分区

c# - 将 .NET 应用程序添加到注册表以在重启后启动以完成某些操作

c++ - 用于创建对象的堆或堆栈?

c++ - 有没有办法继承别名模板?

c++ - 如何访问 C++ 中的实例变量,如 Objective-C getter 和 setter

c - 是否可以使用整数作为数组的名称?

php - HTTP 404 - 找不到文件 Internet Explorer V6