pthread mutex два потока взаимозаменяемо блокирует / разблокирует это правильный подход? - PullRequest
1 голос
/ 12 января 2012

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

У меня есть переменная мьютекса, скажем, myMute, T1, T2 - два потока.

  1. T1 блокирует myMute.

  2. T2 разблокирует myMute.

  3. T2 замки myMute.

  4. T1 разблокирует myMute.

Является ли эта упорядоченная блокировка / разблокировка из разных потоков правильным?

1 Ответ

5 голосов
/ 12 января 2012

Нет, это неправильно.От pthread_mutex_lock man page:

Если поток пытается разблокировать мьютекс, который он не заблокировал, или мьютекс, который разблокирован, это приведет к неопределенному поведению.

Примерправильный порядок:

  • T1 блокирует myMutex
  • T2 блокирует myMutex (заблокировано ожидание, пока T1 разблокирует мьютекс)
  • T1 разблокирует myMutex (теперь T2 блокирует мьютекс)
  • T2 разблокирует myMutex

РЕДАКТИРОВАТЬ:

Небольшой пример с использованием pthread_cond_wait() с проверкой ошибок, опущенной для краткости:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

volatile int value = 0;
pthread_mutex_t mymutex;
pthread_t thread_one;
pthread_t thread_two;
pthread_cond_t cond;

void* main_one(void* ignored)
{
    while (value < 10)
    {
        pthread_mutex_lock(&mymutex);
        pthread_cond_wait(&cond, &mymutex);
        fprintf(stderr, "T1: value=%d\n", value);
        pthread_mutex_unlock(&mymutex);
    }
    return (void*)0;
}

void* main_two(void* ignored)
{
    int i;

    for (i = 0; i < 10; i++)
    {
        pthread_mutex_lock(&mymutex);
        value++;
        fprintf(stderr, "T2: value=%d\n", value);
        pthread_cond_broadcast(&cond);
        fprintf(stderr, "Broadcasted but T1 cannot continue for 1 second\n");
        sleep(1);
        pthread_mutex_unlock(&mymutex);
        pthread_yield();
    }

    return (void*)0;
}

void start_thread(void* (*a_entry_point)(void*),
                  pthread_t* a_handle)
{
    pthread_attr_t thread_attributes;

    pthread_attr_init(&thread_attributes);
    pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
    pthread_create(a_handle, &thread_attributes, a_entry_point, 0);
}

int main()
{
    pthread_mutexattr_t attr;
    pthread_t thread_one_handle;
    pthread_t thread_two_handle;

    /* Init mutex. */
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
    pthread_mutex_init(&mymutex, &attr);

    /* Init condition. */
    pthread_cond_init(&cond, 0);

    /* Start threads. */
    start_thread(main_one, &thread_one_handle);
    start_thread(main_two, &thread_two_handle);

    /* Wait for threads. */
    pthread_join(thread_one_handle, 0);
    pthread_join(thread_two_handle, 0);

    /* Clean up. */
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mymutex);

    return 0;
}

Скомпилировано с gcc -Wall -Werror -D_GNU_SOURCE main.c -o main -pthread.

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