Тупики с pthreads и CreateThread - PullRequest
       45

Тупики с pthreads и CreateThread

4 голосов
/ 20 февраля 2009

Я использую pthreads в приложении Windows. Я заметил, что моя программа зашла в тупик - быстрая проверка показала, что произошло следующее:

Нить 1 порождала Нить 2. Нить 2 порождала Нить 3. Нить 2 ожидала мьютекс из Нити 3, которая не была разблокирована.

Итак, я пошел отлаживать в GDB и получил следующее при возврате третьего потока:

Thread 3 (thread 3456.0x880):
#0  0x7c8106e9 in KERNEL32!CreateThread ()
   from /cygdrive/c/WINDOWS/system32/kernel32.dll
Cannot access memory at address 0x131

Он как-то застрял, заблокирован в функции Windows CreateThread! Очевидно, что он не мог разблокировать мьютекс, когда он даже не мог начать выполнять код. Тем не менее, несмотря на то, что он явно застрял здесь, pthread_create вернул ноль (успех).

Что делает это особенно странным, так это то, что у того же приложения в Linux таких проблем нет. Что в мире может привести к зависанию потока в процессе создания (!?), Но успешному возвращению, как если бы он был создан правильно?

Редактировать: в ответ на запрос кода вот некоторый код (упрощенно):

Создание темы:

if ( pthread_create( &h->lookahead->thread_handle, NULL, (void *)lookahead_thread, (void *)h->thread[h->param.i_threads] ) )
{
    log( LOG_ERROR, "failed to create lookahead thread\n");
    return ERROR;
}
while ( !h_lookahead->b_thread_active )
    usleep(100);
return SUCCESS;

Обратите внимание, что ждет, пока b_thread_active не будет установлен , поэтому каким-то образом устанавливается b_thread_active, поэтому вызываемый поток должен что-то сделать ...

... вот функция lookahead_thread:

void lookahead_thread( mainstruct *h )
{
    h->lookahead->b_thread_active = 1;
    while( !h->lookahead->b_exit_thread && h->lookahead->b_thread_active )
    {
        if ( synch_frame_list_get_size( &h->lookahead->next ) > delay )
            _lookahead_slicetype_decide (h);
        else
            usleep(100);  // Arbitrary number to keep thread from spinning
    }
    while ( synch_frame_list_get_size( &h->lookahead->next ) )
        _lookahead_slicetype_decide (h);
    h->lookahead->b_thread_active = 0;
}

lookahead_slicetype_decide (h); это то, что делает поток.

Мьютекс, synch_frame_list_get_size:

int   synch_frame_list_get_size( synch_frame_list_t *slist )
{
    int fno = 0;

    pthread_mutex_lock( &slist->mutex );
    while (slist->list[fno]) fno++;
    pthread_mutex_unlock( &slist->mutex );
    return fno;
}

Обратный след нити 2:

Thread 2 (thread 332.0xf18):
#0  0x00478853 in pthread_mutex_lock ()
#1  0x004362e8 in synch_frame_list_get_size (slist=0x3ef3a8)
    at common/frame.c:1078
#2  0x004399e0 in lookahead_thread (h=0xd33150)
    at encoder/lookahead.c:288
#3  0x0047c5ed in ptw32_threadStart@4 ()
#4  0x77c3a3b0 in msvcrt!_endthreadex ()
   from /cygdrive/c/WINDOWS/system32/msvcrt.dll
#5  0x7c80b713 in KERNEL32!GetModuleFileNameA ()
   from /cygdrive/c/WINDOWS/system32/kernel32.dll
#6  0x00000000 in ?? 

1 Ответ

1 голос
/ 20 февраля 2009

Я бы попробовал дважды проверить ваши мьютексы в потоке 2 и потоке 3. Pthreads реализованы для окон, используя стандартный windows api; Таким образом, между версиями Windows и Linux будут небольшие различия. Это странная проблема, но опять же, это часто случается в потоке.

Не могли бы вы опубликовать фрагмент кода, в котором выполняется блокировка в потоке 2 и в функции, в которой должен запускаться поток 3?

Редактировать в ответ на код

Вы когда-нибудь разблокировали мьютекс в потоке 2? Ваша трассировка показывает, что он блокирует мьютекс, затем создает поток, который выполняет всю эту работу, которая пытается также заблокировать мьютекс. Я думаю, после того, как поток 2 возвращает SUCESS это делает? Кроме того, почему вы используете флаги и спящий режим, возможно, барьеры или условные переменные для синхронизации процессов могут быть более надежными.

Еще одно замечание, помечен ли флаг b_thread_active как volatile? Возможно, компилятор что-то кеширует, чтобы не дать ему сработать?

...