我用C編寫多線程程序,目前我需要重新啓動該程序每次我進行了更改配置文件時,我的應用程序還支持標準SIGHUP信號重新加載配置,但需要人工干預。配置自動重新加載與並行線程
爲了解決這個問題,我寫了一個獨立的線程讀取配置文件並加載它,並隨時監控該文件的任何修改。
的問題是,如何通知有關配置更改安全而不影響巨大互斥鎖性能的其他線程。
我想有每個配置變化的版本號,這樣一來我就只需要鎖定config_ver變量的變化,並保留舊的配置較慢的線程訪問。
任何想法,將不勝感激。
我用C編寫多線程程序,目前我需要重新啓動該程序每次我進行了更改配置文件時,我的應用程序還支持標準SIGHUP信號重新加載配置,但需要人工干預。配置自動重新加載與並行線程
爲了解決這個問題,我寫了一個獨立的線程讀取配置文件並加載它,並隨時監控該文件的任何修改。
的問題是,如何通知有關配置更改安全而不影響巨大互斥鎖性能的其他線程。
我想有每個配置變化的版本號,這樣一來我就只需要鎖定config_ver變量的變化,並保留舊的配置較慢的線程訪問。
任何想法,將不勝感激。
使用gcc的原子操作就可以快速測試,如果一個配置改變(時間比較兩個整數),你可以加載新CONFIGS ...所有沒有鎖定。
的僞代碼:
可以說,我有一個配置結構C.要有一個全局變量_pConfig指向當前的配置。
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是一個指向線程數據的指針。
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因爲多個線程可以同時訪問該新的配置,這保證了精確的使用次數。
注意的調出點A和B之間由於時間片線程的暫停時間通常爲1毫秒,長失速可能是10-100毫秒,除非調度大清洗。如果你的配置數據很小並且一小時只能改變幾次,那麼我可能會持續好幾天才能解放它。選擇一個足夠長的時間,以便知道沒有停滯的線程。不要擔心,如果一個線程出於某種原因沒有長時間檢查一個新的配置...使用計數將大於1,它不會被釋放。
如果您在釋放舊配置之前等待足夠長的時間,或者根本沒有釋放它們,引用計數可能是過量的。這個解決方案的重要概念是你創建一個新的配置結構,允許線程仍然使用舊的配置,直到他們注意到這個變化。 – johnnycrash 2011-04-06 20:59:35