Инициализация библиотеки - pthread_once в реализации Win32 - PullRequest
4 голосов
/ 10 марта 2009

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


void libInit (void)
{
#ifdef WIN32
    static volatile int initialized = 0;
    static HANDLE mtx;

    if (!initialized)
    {
        if (!mtx)
        {
            HANDLE mymtx;
            mymtx = CreateMutex(NULL, 0, NULL);
            if (InterlockedCompareExchangePointer(&mtx, mymtx, NULL) != NULL)
                CloseHandle(mymtx);
        }

        WaitForSingleObject(mtx);
        if (!initialized)
        {
            libInitInternal();
            initialized = 1;
        }
        ReleaseMutex(mtx);
    }
#else
    static pthread_once_t initialized = PTHREAD_ONCE_INIT;

    pthread_once(&initialized, libInitInternal);
#endif
}

Вызов libInitInternal() приводит к небезопасной функции, которая инициализирует библиотеку.

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

Ответы [ 5 ]

6 голосов
/ 11 марта 2009

Я думаю, вы хотите использовать функцию Единовременная инициализация . В синхронном режиме все потоки блокируются, пока не завершится первый поток, вызвавший его. Похоже на pthread_once ().

Здесь пример кода .

Итак, в вашем случае вы бы сказали:

BOOL CALLBACK CallLibInitInternal(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) {
    libInitInternal();
    return TRUE;
}

void libInit() {
#ifdef WIN32
    static INIT_ONCE s_init_once;
    InitOnceExecuteOnce(&s_init_once, CallLibInitInternal, NULL, NULL);
#else
...
#endif
}
3 голосов
/ 22 марта 2009

Возможно, вы захотите проверить, что pthreads-win32 делает в своей реализации pthread_once () . или просто используйте это, если это окажется легче.

2 голосов
/ 12 апреля 2011

При использовании GCC или clang вы можете использовать атрибуты конструктора и деструктора. Они работают как с общими, так и со статическими библиотеками и выполняют код до и после запуска main, соответственно. Кроме того, вы можете указать несколько функций конструктора и деструктора. Гораздо чище, чем синглтонный подход, и не требует от вас вызова libInit () из вашего main ().

static void __attribute__((constructor))
your_lib_init(void)
{
    fprintf(stderr, "library init\n");
}

static void __attribute__((destructor))
vensim_ctx_destroy(void)
{
    fprintf(stderr, "library destroy\n");
}
2 голосов
/ 11 марта 2009

Посмотрев следующий исходный код для pthread_once () (из здесь ), похоже, вы на правильном пути.

int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
    /* Check first for speed */
    if (once_control->state == PTHREAD_NEEDS_INIT) {
        pthread_mutex_lock(&(once_control->mutex));
        if (once_control->state == PTHREAD_NEEDS_INIT) {
            init_routine();
            once_control->state = PTHREAD_DONE_INIT;
        }
        pthread_mutex_unlock(&(once_control->mutex));
    }
    return(OK);
}

Кстати, я буду использовать pthread_once () для замены некоторых довольно запутанных функций в моем коде.

0 голосов
/ 11 марта 2009

Я бы проверил эту статью. Это решение для синглетонов C ++, но я считаю, что вы можете использовать это решение и для своего кода: http://www.ddj.com/cpp/199203083?pgno=1

К сожалению, список для самого QLock отсутствует, похоже, что они пытаются продать компакт-диск, но, похоже, его достаточно, чтобы написать один.

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