处理多线程c ++服务器应用程序中的非常量全局配置

goj*_*oji 2 c++ configuration multithreading global-variables thread-safety

我正在设计一个多线程c ++服务器应用程序,它在自己的线程中为客户端提供服务,还有各种其他工作线程来执行其他任务.

所有这些线程都依赖于单个文本配置文件,该文件需要能够在不退出并重新启动进程的情况下重新进行.

我目前正在考虑让每个客户端和工作线程拥有它自己的配置对象副本,然后在每次重新散列时都有这个更新.

我发现这一点的一件事是将配置传递给我更喜欢的所有其他实用功能,并且不认为应该是上述类的一部分看起来非常单调乏味.

除了对大量同步的痛苦需求之外,拥有全局配置会更加容易.

打开任何关于如何在线程应用程序中解决非常量全局配置的想法!

ric*_*ici 5

我喜欢这样做的方法是始终将config作为shared_ptr传递给const对象.无论什么时候需要配置(保持一致性;使用相同的配置处理整个请求通常更好,即使配置在请求处理代码的末尾在技术上已经过时),您也会得到一个shared_ptr.后台工作程序任务可以在工作周期的方便点重置其shared_ptr的值,试图避免保持配置太长时间(因为它可能会过时).

如果只有一个任务可以更改配置,这很好用; 它构造一个全新的配置对象,然后重置它的shared_ptr,[edit]它用一个锁保护,见下面的[/ edit].只要没有其他任务使用旧的配置对象,旧配置对象就会消失.

一个细节:您不能传递指向配置对象部分的指针,除非您确定只要指针将持续,您将继续将shared_ptr保留到该配置对象.如果配置包括例如子配置的名称映射,则这可能是恼人的.

虽然共享指针有一些开销,但它可能不会使配置的整个副本保持同步(当然,除非配置很小,否则我们可能不会进行此对话).在大多数应用程序中,配置更改相对较少,因此在任何给定时间您都不太可能拥有两个以上的配置对象.您通常可以安排将shared_ptr创建保留为每个请求一个,因此shared_ptr同步很简单.

YMMV,但我发现它运作得很好.

[编辑]正如一些评论者指出的那样,我应该明确关于锁定要求.配置更新程序保留一个主设备shared_ptr,该主设备受读写锁保护.它需要在更新指针时保持写锁定.它还导出一个接口,该接口将shared_ptr返回给当前配置; 该接口在保持读锁定的同时复制shared_ptr.由于配置更改很少且shared_ptr很小,因此锁争用很少.[1]

除了配置任务本身之外,没有其他人需要担心锁定,因为其他shared_ptr不应该被多个任务共享:每个任务都应该自己获得.

[1]当我写这篇文章的时候,我意识到我一直这样做的方法,包括在master shared_ptr上调用.reset,如果配置的析构函数很慢,实际上可能会保持写锁定的时间太长(如果例如,配置包含大量的std :: string.最好扩展reset的实现(这只是一个带有临时NULL shared_ptr的交换),将交换放在锁定保护之内,让析构函数(临时的)运行解锁.但是,考虑到配置变化的罕见性(至少在我所关联的任何服务器中),我怀疑它是否会产生任何明显的差异.