Автоматическая перезагрузка конфигурации с помощью pthreads - PullRequest
0 голосов
/ 19 марта 2011

Я пишу многопоточную программу на C, в настоящее время мне нужно перезапускать программу каждый раз, когда я вносю изменения в файл конфигурации, мое приложение также поддерживает стандартный сигнал SIGHUP для перезагрузки конфигурации, но это требует ручного вмешательства.

Чтобы решить эту проблему, я написал отдельную ветку, которая читает файл конфигурации и загружает его, и продолжает следить за этим файлом на предмет любых изменений.

Вопрос в том, как уведомить другие темы оИзменение конфигурации безопасно и без ущерба для производительности с огромными блокировками мьютекса.

Я думаю о том, чтобы иметь номер версии для каждого изменения конфигурации, таким образом, мне нужно было бы только заблокировать изменения переменных config_ver и сохранить старые конфигурации доступными дляболее медленные темы.

Любая идея будет оценена.

1 Ответ

1 голос
/ 06 апреля 2011

Используя атомарные операции gcc, вы можете быстро проверить, изменился ли конфиг (время для сравнения двух целых), и вы можете загрузить новые конфиги ... ВСЕ БЕЗ БЛОКИРОВКИ.

Код Psuedo:

Допустим, у меня была структура конфигурации 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, и он не будет освобожден.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...