2011-03-19 18 views
0

我用C編寫多線程程序,目前我需要重新啓動該程序每次我進行了更改配置文件時,我的應用程序還支持標準SIGHUP信號重新加載配置,但需要人工干預。配置自動重新加載與並行線程

爲了解決這個問題,我寫了一個獨立的線程讀取配置文件並加載它,並隨時監控該文件的任何修改。

的問題是,如何通知有關配置更改安全而不影響巨大互斥鎖性能的其他線程。

我想有每個配置變化的版本號,這樣一來我就只需要鎖定config_ver變量的變化,並保留舊的配置較慢的線程訪問。

任何想法,將不勝感激。

回答

1

使用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,它不會被釋放。

+0

如果您在釋放舊配置之前等待足夠長的時間,或者根本沒有釋放它們,引用計數可能是過量的。這個解決方案的重要概念是你創建一個新的配置結構,允許線程仍然使用舊的配置,直到他們注意到這個變化。 – johnnycrash 2011-04-06 20:59:35