使用 pthreads 自动重新加载配置 [英] Configuration auto reloading with pthreads
问题描述
我正在用 C 编写多线程程序,目前我每次更改配置文件时都需要重新启动程序,我的应用程序也支持标准的 SIGHUP 信号来重新加载配置,但这需要手动干预.
I am writing multi threaded program in C, currently I need to restart the program every time I make a change to the configuration file, my application also support the standard SIGHUP signal to reload the configuration, but this need manual intervention.
为了解决这个问题,我写了一个单独的线程来读取配置文件并加载它,并持续监控这个文件的任何变化.
To solve this, I wrote a separate thread that read the configuration file and load it, and keep monitoring this file for any changes.
问题是,如何在不影响性能的情况下安全地通知其他线程有关配置更改的巨大互斥锁.
The question is, how to notify other threads about a configuration change safely and without affecting the performance with huge mutex locks.
我正在考虑为每个配置更改设置一个版本号,这样我只需要锁定 config_ver 变量更改,并让较慢的线程可以访问旧配置.
I am thinking of having a version number for each configuration change, this way I would only need to lock config_ver variable changes, and keep old configurations accessible for slower threads.
任何想法将不胜感激.
推荐答案
使用 gcc 原子操作,您可以快速测试配置是否更改(比较两个整数的时间),并且您可以加载新配置...无需锁定.
Using gcc atomic operations you can quickly test if a config changed (time to compare two ints) and you can load new configs...ALL WITHOUT LOCKING.
伪代码:
假设我有一个配置结构 C.让有一个全局变量 _pConfig 指向当前配置.
Lets say I had a configuration struct C. Let there be a global variable _pConfig which points to the current config.
struct C *_pConfig;
加载新配置:
// allocate a new struct C
struct C *pNewconfig = malloc(sizeof(struct C));
...
// load the pNewconfig struct from disk or something
...
// let the config struct have a next pointer so we can save list of configs for freeing later
pNewconfig->pNext = _pConfig;
// when done loading pNewconfig. change the global. not before done!, else threads see unf data!
// 32 bit assignment is atomic (usually).
// If not atomic on your platform, use __sync_bool_compare_and_swap()
_pConfig = pNewConfig;
// is safe to free old cfgs with 0 use counts. Make sure old is old enough so that there is no chance
// a thread could have been swapped out anywhere between point A and B below (next code section).
for (struct C *pCfg=pNewconfig->pNext ; pCfg ; pCfg=pCfg->pNext) {
// Free last pcfg (!pCfg->pNext) if its not in use and its old enough.
// Don't have to atomically check cUse here since once it changes to zero, its zero forever.
// nBirthday could be clock ticks when the config was created. nNow could be ticks now.
if (!pCfg->pNext && !pCfg->cUse && pCfg->nBirthDay-nNow > OldEnough) {
free(pCfg);
break;
}
}
现在我们如何使用它...每个线程需要保留一个 ptr 来构造线程配置的 C 结构.如果 _pConfig 发生变化,每个线程都可以通过将线程的 C 结构地址与当前地址进行比较来判断.假设 pthread 是指向线程数据的指针.
Now how do we use this... Each thread needs to keep a ptr to struct C the thread was configured with. If _pConfig changes, each thread can tell by comparing the thread's struct C address to the current one. Assume pthread is a pointer to the thread's data.
while (1) {
// POINT A
struct C *pConfig = _pConfig; // make a copy in case it changes
// super quick check with no locking!
if (pConfig == pThread->pConfig)
break; // no change...get out quick.
__sync_add_and_fetch(&pConfig->cUse, 1); // increment use count of new cfg
// POINT B
__sync_sub_and_fetch(&pThread->pConfig->cUse, 1); // decriment use count of thread's cfg
pThread->pConfig = pConfig; // use new cfg
// do whatever you do with the cfg data
}
使用 __sync_add, _sub 因为多个线程可以同时访问新配置,这可以确保准确的使用计数.
Use __sync_add, _sub because multiple threads can be accessing the new config at the same time and this ensures an accurate use count.
请注意在 A 点和 B 点之间调度的线程的停顿时间.由于时间片通常为 1 毫秒,因此长时间停顿可能是 10-100 毫秒,除非调度程序被冲洗掉.如果您的配置数据很小并且每小时只更改几次,我可能会在释放它之前保留它几天.选择一个足够大的时间,您知道没有停滞的线程.如果某个线程由于某种原因长时间未检查新配置,请不要担心...使用计数将 > 1 并且不会被释放.
Be aware of the stall time of a thread scheduled out between point A and B. Since a time slice is usually 1 ms, a long stall might be a 10-100 ms, unless the scheduler is hosed. If your configuration data is small and changes only a couple times an hour, I might hold onto it for days before freeing it. Pick a big enough time that you know there are no stalled threads. Don't worry if a thread for some reason hasn't checked for a new config in a long time...the use count will be > 1 and it wont be freed.
这篇关于使用 pthreads 自动重新加载配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!