Проверьте, не заблокирован ли мьютекс pthread (разблокирован ли поток) - PullRequest
14 голосов
/ 06 декабря 2010

Мне нужно посмотреть, заблокирован ли мьютекс в операторе if, поэтому я проверяю его следующим образом ...

if(mutex[id] != 2){
    /* do stuff */
}

но когда я проверяю это, gcc выдает следующую ошибку:

error: invalid operands to binary != (have 'ptherad_mutex_t' and 'int')

Так, как я могу проверить, заблокирован ли мьютекс или нет?

EDIT:

Ключевым компонентом моей проблемы является то, что мои потоки (по своему замыслу) блокируются сразу после передачи управления другому потоку. Таким образом, когда поток A передает управление потоку B, поток A блокируется, поток B выполняет некоторые действия, а затем, когда поток B завершается, он разблокирует поток A.

Проблема в том, что если поток B пытается разблокировать поток A, а поток A еще не завершил саму блокировку, то вызов для разблокировки теряется, а поток A остается заблокированным, что вызывает мертвую блокировку.

UPDATE:

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

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

#include <pthread.h>

int run_a = 0;
pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;

int run_b = 0;
pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;

void *a(void *);
void *b(void *);

int main(){
    int status;
    pthread_t thread_a;
    pthread_t thread_b;

    pthread_create(&thread_a, NULL, a, (void *)0);
    pthread_create(&thread_b, NULL, b, (void *)0);

    pthread_join(thread_a, (void **)&status);
    pthread_join(thread_b, (void **)&status);

}

/* thread A */
void *a(void *i){
    while (1) {
        printf("thread A is running\n");
        sleep(1);

        /* unlock thread B */
        pthread_mutex_lock(&lock_b);
            run_b = 1;
            pthread_cond_signal(&cond_b);
        pthread_mutex_unlock(&lock_b);

        /* wait for thread A to be runnable */
        pthread_mutex_lock(&lock_a);
            while (!run_a)
                pthread_cond_wait(&cond_a, &lock_a);
            run_a = 0;
        pthread_mutex_unlock(&lock_a);      
    }
}

/* thread B */
void *b(void *i){
    while (1) {
        /* wait for thread B to be runnable */
        pthread_mutex_lock(&lock_b);
            while (!run_b)
                pthread_cond_wait(&cond_b, &lock_b);
            run_b = 0;
        pthread_mutex_unlock(&lock_b);

        printf("thread B is running\n");
        sleep(1);

        /* unlock thread A */
        pthread_mutex_lock(&lock_a);
            run_a = 1;
            pthread_cond_signal(&cond_a);
        pthread_mutex_unlock(&lock_a);
    }
}

Ответы [ 3 ]

20 голосов
/ 06 декабря 2010

Вы можете использовать pthread_mutex_trylock. Если это удастся, мьютекс был невостребован, и теперь вы им владеете (поэтому вы должны освободить его и вернуть «unheld», в вашем случае). В противном случае кто-то его держит.

Я должен подчеркнуть, что «проверить, является ли мьютекс невостребованным», - очень плохая идея. В этом типе мышления есть неотъемлемые расовые условия. Если такая функция сообщает вам во время t, что блокировка не удержана, это абсолютно ничего не говорит о том, что какой-то другой поток получил блокировку в t+1.

.

В случае, если это лучше проиллюстрировано на примере кода, рассмотрим:

bool held = is_lock_held();

if (!held)
{
  // What exactly can you conclude here?  Pretty much nothing.
  // It was unheld at some point in the past but it might be held
  // by the time you got to this point, or by the time you do your
  // next instruction...
}
19 голосов
/ 06 декабря 2010

Мьютексы не являются правильным примитивом для схемы, которую вы хотите реализовать. Вы должны использовать условные переменные :

int run_thread_a = 0;
pthread_mutex_t run_lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_a = PTHREAD_COND_INITIALIZER;

int run_thread_b = 0;
pthread_mutex_t run_lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_b = PTHREAD_COND_INITIALIZER;

/* thread A */
while (1) {
    /* Wait for Thread A to be runnable */
    pthread_mutex_lock(&run_lock_a);
    while (!run_thread_a)
        pthread_cond_wait(&run_cond_a, &run_lock_a);
    run_thread_a = 0;
    pthread_mutex_unlock(&run_lock_a);

    /* Do some work */

    /* Now wake thread B */
    pthread_mutex_lock(&run_lock_b);
    run_thread_b = 1;
    pthread_cond_signal(&run_cond_b);
    pthread_mutex_unlock(&run_lock_b);
}

/* thread B */
while (1) {
    /* Wait for Thread B to be runnable */
    pthread_mutex_lock(&run_lock_b);
    while (!run_thread_b)
        pthread_cond_wait(&run_cond_b, &run_lock_b);
    run_thread_b = 0;
    pthread_mutex_unlock(&run_lock_b);

    /* Do some work */

    /* Now wake thread A */
    pthread_mutex_lock(&run_lock_a);
    run_thread_a = 1;
    pthread_cond_signal(&run_cond_a);
    pthread_mutex_unlock(&run_lock_a);
}

Каждый поток будет блокироваться в pthread_cond_wait(), пока другой поток не подаст сигнал на его пробуждение. Это не заблокирует.

Его можно легко расширить на множество потоков, выделив по одному int, pthread_cond_t и pthread_mutex_t на поток.

1 голос
/ 06 декабря 2010

Вы не можете сравнить pthread_mutex_t с целым числом.

Вы можете использовать

int pthread_mutex_trylock(pthread_mutex_t *mutex);

, чтобы проверить это.

...