2011-03-19 4 views
0

나는 다중 스레드 프로그램을 C로 작성하고 있는데, 현재 구성 파일을 변경할 때마다 프로그램을 다시 시작해야하며, 응용 프로그램도 구성을 다시로드하기 위해 표준 SIGHUP 신호를 지원하지만이 수동 개입이 필요합니다.구성 자동 재로드와 pthreads

이 문제를 해결하기 위해 구성 파일을 읽고로드 한 별도의 스레드를 작성하고 변경 사항에 대해이 파일을 계속 모니터링합니다.

질문은 거대한 뮤텍스 잠금 성능에 영향을 미치지 않고 구성 변경 사항을 안전하게 다른 사람에게 알리는 방법입니다.

각 구성 변경에 대한 버전 번호가 필요하다고 생각합니다.이 방법을 사용하면 config_ver 변수 변경 내용을 잠그고 느린 스레드에 대한 이전 구성 액세스를 유지해야합니다.

어떤 아이디어라도 감사 할 것입니다.

답변

1

gcc 원자 연산을 사용하면 구성이 변경되었는지 (두 int를 비교할 시간) 새 구성을로드 할 수 있는지 신속하게 테스트 할 수 있습니다. 잠금없이 모두.

사이비 코드 :

내가 구성했다 구조체 C.가 보자 현재 설정을 가리키는 전역 변수 _pConfig 수 말할 수 있습니다. 우리는이 ... 각 스레드가 스레드로 구성된 C 구조체하는 PTR을 유지하기 위해 필요 어떻게 사용합니까 지금

// 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; 
    } 
} 

:

struct C *_pConfig; 

는 새로운 설정을로드합니다. _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 사이에 스케줄 된 스레드의 정지 시간을 알고 있어야합니다. 시간 조각은 일반적으로 1ms이므로 스케줄러가 닫히지 않는 한 긴 정지는 10-100ms가 될 수 있습니다. 구성 데이터가 작고 한 시간에 몇 번만 변경되는 경우, 며칠 동안 그것을 풀어 놓은 후에 해제 할 수 있습니다. 스톨 된 스레드가 없다는 것을 알 수있는 충분한 시간을 선택하십시오. 어떠한 이유로 든 스레드가 오랫동안 새로운 설정을 확인하지 않았다면 걱정하지 마십시오 ... 사용 횟수가 1보다 많아서 해제되지 않습니다.

+0

이전 구성을 해제하기 전에 충분히 오래 기다리거나 참조 설정을 전혀 해제하지 않으면 참조 카운팅이 과장 될 수 있습니다. 이 솔루션의 중요한 개념은 새로운 구성 구조를 만들어 스레드가 변경 사항을 알기 전까지 이전의 스레드를 계속 사용할 수있게하는 것입니다. – johnnycrash