Отмена зависания функции pthread_cond_wait() с помощью мьютекса PRIO_INHERIT

Обновление, 4/10 2012: исправлено исправлением libc


У меня проблема с отменой тем в pthread_cond_wait, которые используют мьютексы с PTHREAD_PRIO_INHERIT набор атрибутов. Это происходит только на определенных платформах.

Следующий минимальный пример демонстрирует это: (скомпилировать с g++ <filename>.cpp -lpthread)

#include <pthread.h>
#include <iostream>

pthread_mutex_t mutex;
pthread_cond_t cond;

void clean(void *arg) {
    std::cout << "clean: Unlocking mutex..." << std::endl;
    pthread_mutex_unlock((pthread_mutex_t*)arg);
    std::cout << "clean: Mutex unlocked..." << std::endl;
}

void *threadFunc(void *arg) {
    int ret = 0;
    pthread_mutexattr_t mutexAttr;
    ret = pthread_mutexattr_init(&mutexAttr); std::cout << "ret = " << ret << std::endl;

    //Comment out the following line, and everything works
    ret = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); std::cout << "ret = " << ret << std::endl;

    ret = pthread_mutex_init(&mutex, &mutexAttr); std::cout << "ret = " << ret << std::endl;
    ret = pthread_cond_init(&cond, 0); std::cout << "ret = " << ret << std::endl;

    std::cout << "threadFunc: Init done, entering wait..." << std::endl;

    pthread_cleanup_push(clean, (void *) &mutex);
    ret = pthread_mutex_lock(&mutex); std::cout << "ret = " << ret << std::endl;
    while(1) {
        ret = pthread_cond_wait(&cond, &mutex); std::cout << "ret = " << ret << std::endl;
    }
    pthread_cleanup_pop(1);

    return 0;
}

int main() {
    pthread_t thread;
    int ret = 0;
    ret = pthread_create(&thread, 0, threadFunc, 0); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Thread created, waiting a bit..." << std::endl;
    sleep(2);

    std::cout << "main: Cancelling threadFunc..." << std::endl;
    ret = pthread_cancel(thread); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Joining threadFunc..." << std::endl;
    ret = pthread_join(thread, NULL); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Joined threadFunc, done!" << std::endl;
    return 0;
}

Каждый раз, когда я запускаю его, main() висит на pthread_join(), Обратный след GDB показывает следующее:

Thread 2 (Thread 0xb7d15b70 (LWP 257)):
#0  0xb7fde430 in __kernel_vsyscall ()
#1  0xb7fcf362 in __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:142
#2  0xb7fcc9f9 in __condvar_w_cleanup () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/pthread_cond_wait.S:434
#3  0x08048fbe in threadFunc (arg=0x0) at /home/pthread_cond_wait.cpp:22
#4  0xb7fc8ca0 in start_thread (arg=0xb7d15b70) at pthread_create.c:301
#5  0xb7de73ae in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130

Thread 1 (Thread 0xb7d166d0 (LWP 254)):
#0  0xb7fde430 in __kernel_vsyscall ()
#1  0xb7fc9d64 in pthread_join (threadid=3083950960, thread_return=0x0) at pthread_join.c:89
#2  0x0804914a in main () at /home/pthread_cond_wait.cpp:41

Если PTHREAD_PRIO_INHERIT не установлен на мьютекс, все работает как надо, и программа завершает работу чисто.

Платформы с проблемами:

  • Встроенная плата AMD Fusion, работающая на 32-битной Linux 3.2.9-rt16 на базе PTXDist (с RTpatch 16). Мы используем новейший кросс-инструментарий OSELAS i686 (2011.11.1), используя gcc 4.6.2, glibc 2.14.1, binutils 2.21.1a, ядро ​​2.6.39.
  • Та же плата с набором инструментов 2011.03.1 (gcc 4.5.2 / glibc 2.13 / binutils 2.18 / ядро ​​2.6.36).

Платформы без проблем:

  • Наша собственная ARM-плата, также работающая под управлением PTXDist Linux (32-разрядная версия 2.6.29.6-rt23), использующая перекрестный набор инструментов OSELAS arm-v4t (1.99.3) с gcc 4.3.2 / glibc 2.8 / binutils 2.18 / ядро ​​2.6.27,
  • Мой ноутбук (Intel Core i7) под управлением 64-разрядной версии Ubuntu 11.04 (виртуализированный / ядро ​​2.6.38.15-generic), gcc 4.5.2 / eglibc 2.13-0ubuntu13.1 / binutils 2.21.0.20110327.

Я искал решения в сети и наткнулся на несколько исправлений, которые я пробовал, но безрезультатно:

Мы делаем что-то не так в нашем коде, который просто работает на определенных платформах, или это ошибка в базовых системах? Если у кого-нибудь есть идеи о том, где искать, или кто-нибудь знает какие-либо исправления или аналогичные варианты, я буду рад узнать об этом.

Спасибо!

Обновления:

1 ответ

Решение

Это было исправлено исправлением libc. Я подтвердил, что он работает на моей собственной проблемной платформе (нашей пользовательской плате AMD Fusion), исправленной на glibc-2.14.1.

Спасибо за помощь Сиддхешу Поярекару!

Другие вопросы по тегам