Pthread Mutex блокирует разблокировку различными потоками
Наивный вопрос..
Я читаю, прежде чем говорить - " MUTEX должен быть разблокирован только потоком, который его заблокировал."
Но я написал программу, где THREAD1 блокирует mutexVar и идет на сон. Затем THREAD2 может непосредственно разблокировать mutexVar, выполнить некоторые операции и вернуться.
== > Я знаю, что все говорят, почему я так делаю? Но мой вопрос: это правильное поведение MUTEX??
== > Добавление примерного кода
void *functionC()
{
pthread_mutex_lock( &mutex1 );
counter++;
sleep(10);
printf("Thread01: Counter value: %d\n",counter);
pthread_mutex_unlock( &mutex1 );
}
void *functionD()
{
pthread_mutex_unlock( &mutex1 );
pthread_mutex_lock( &mutex1 );
counter=10;
printf("Counter value: %d\n",counter);
}
int main()
{
int rc1, rc2;
pthread_t thread1, thread2;
if(pthread_mutex_init(&mutex1, NULL))
printf("Error while using pthread_mutex_init\n");
if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &functionD, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
Ответы
Ответ 1
То, что вы сделали, просто не является законным, а поведение - undefined. Мьютексы только исключают потоки, которые играют по правилам. Если вы попытались заблокировать mutex1 из потока 2, поток будет заблокирован, конечно; что нужно делать. В спецификации нет ничего, что говорит о том, что произойдет, если вы попытаетесь разблокировать мьютексы, которыми вы не владеете!
Ответ 2
Pthreads имеет 3 разных типа мьютексов: быстрый мьютекс, рекурсивный мьютекс и мьютекс с проверкой ошибок. Вы использовали быстрый мьютекс, который по соображениям производительности не проверяет эту ошибку. Если вы используете проверку ошибок mutex в Linux, вы обнаружите, что получаете ожидаемые результаты.
Ниже приведен небольшой пример вашей программы в качестве примера и доказательства. Он блокирует мьютексы в main(), и разблокировка в созданном потоке завершится с ошибкой.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
/*** NOTE THE ATTR INITIALIZER HERE! ***/
pthread_mutex_t mutex1 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
int counter = 0;
void *functionD(void* data)
{
int rc;
if ((rc = pthread_mutex_unlock(&mutex1)) != 0)
{
errno = rc;
perror("other thread unlock result");
exit(1);
}
pthread_mutex_lock(&mutex1);
counter=10;
printf("Thread02: Counter value: %d\n",counter);
return(data);
}
int main(int argc, char *argv[])
{
int rc1;
pthread_t thread1;
if ((rc1 = pthread_mutex_lock(&mutex1)) != 0)
{
errno = rc1;
perror("main lock result");
}
if( (rc1 = pthread_create(&thread1, NULL, &functionD, NULL)))
{
printf("Thread creation failed: %d\n", rc1);
}
pthread_join(thread1, NULL);
}
Ответ 3
Мьютекс используется для предотвращения выполнения несколькими потоками кода, который является безопасным только для одного потока за раз.
Для этого мьютекс имеет несколько функций:
-
Мьютекс может обрабатывать условия гонки, связанные с несколькими потоками, пытаясь "заблокировать" мьютекс в одно и то же время и всегда приводит к тому, что один поток выигрывает гонку.
-
Любая нить, которая теряет гонку, засыпает постоянно, пока мьютекс не разблокируется. Мьютекс поддерживает список этих потоков.
-
A передаст "блокировку" одному и только одному из ожидающих потоков, когда мьютекс будет разблокирован потоком, который просто использовал его. Мьютекс разбудит эту нить.
Если этот тип шаблона полезен для какой-либо другой цели, тогда используйте его по другой причине.
Вернемся к вашему вопросу. Допустим, вы защищали некоторый код из нескольких потоков доступа с помощью мьютекса и разрешали говорить, что 5 потоков ожидали, когда поток A выполнял код. Если нить B (ни одна из тех, которые ждут с тех пор, как они постоянно спали в данный момент) разблокирует мьютекс, другой поток начнет выполнение кода одновременно с потоком A. Вероятно, не требуется.
Возможно, если бы мы знали, что вы думаете об использовании мьютекса, мы могли бы дать лучший ответ. Вы пытаетесь разблокировать мьютекс после отмены потока? У вас есть код, который может обрабатывать 2 потока за раз, но не три, и нет мьютекса, который пропускает по два потока за раз?