Pthread互斥锁由不同的线程解锁

Posted

技术标签:

【中文标题】Pthread互斥锁由不同的线程解锁【英文标题】:Pthread Mutex lock unlock by different threads 【发布时间】:2011-07-24 05:00:12 【问题描述】:

一个幼稚的问题..

我之前读到过 -“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);
    

【问题讨论】:

@Santiago - 添加了示例代码.. NO -- 但值为 1 的 SEMAPHORE 可以像互斥锁一样,并且可以从不同的线程解锁。但是,您可能需要使用互斥锁来保护信号量上的操作,以阻止其值超过 1。 【参考方案1】:

您所做的根本不合法,并且行为未定义。互斥锁只排除遵守规则的线程。如果您试图从线程 2 中锁定 mutex1,那么该线程当然会被阻塞;这是必须要做的事情。规范中没有说明如果您尝试解锁不属于您的互斥锁会发生什么!

【讨论】:

感谢您的回复。但是当基础说 thread2 无法解锁 thread1 持有的互斥锁时,为什么 PThreads 的实现会有所不同?? @codingfreak:API 不是一件紧身衣。文档是说“不要那样做”,而不是“我们会积极阻止你那样做”。计算机并不总是阻止你做你不应该做的事情。这是一个相当基本的概念,随着您的学习,它会一次又一次地出现:您可以做各种各样的事情,其中​​许多事情是您不应该做的,并且如果您这样做了,则会有未定义的行为。这就像说“你不能酒后驾车”——没有任何机制积极阻止你这样做,但你仍然不应该这样做。 很遗憾 pthread mutex 使得 Raynal 的读写同步无法实现:en.wikipedia.org/wiki/Readers%E2%80%93writer_lock【参考方案2】:

Pthreads 有 3 种不同类型的互斥锁:快速互斥锁、递归互斥锁和错误检查互斥锁。您使用了快速互斥体,出于性能原因,它不会检查此错误。如果你在 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);

【讨论】:

在 Linux 上使用 -D_GNU_SOURCE 编译。 这应该是公认的答案,更完整!请注意:PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 不可移植!【参考方案3】:

互斥锁用于防止多个线程执行一次只对一个线程安全的代码。

要做到这一点,互斥体有几个特点:

    互斥锁可以处理与尝试同时“锁定”互斥锁的多个线程相关的竞争条件,并且始终导致一个线程赢得竞争。

    任何失去竞争的线程都会永久进入休眠状态,直到互斥锁被解锁。互斥体维护这些线程的列表。

    当互斥锁被刚刚使用它的线程解锁时,A 会将“锁”交给一个且仅一个等待线程。互斥锁将唤醒该线程。

如果这种类型的模式对其他目的有用,那么请继续将其用于其他目的。

回到你的问题。假设您正在使用互斥锁保护某些代码免受多线程访问,假设线程 A 正在执行代码时有 5 个线程正在等待。如果线程 B(不是等待的线程之一,因为它们此时永久处于休眠状态)解锁互斥锁,另一个线程将与线程 A 同时开始执行代码。可能不需要。

也许如果我们知道您对使用互斥锁的想法,我们可以给出更好的答案。您是否在取消线程后尝试解锁互斥锁?您是否有一次可以处理 2 个线程但不能处理 3 个线程的代码,并且没有可以一次允许 2 个线程通过的互斥锁?

【讨论】:

以上是关于Pthread互斥锁由不同的线程解锁的主要内容,如果未能解决你的问题,请参考以下文章

C++ Pthread 互斥锁

PTHREAD 互斥锁是只避免同时访问资源,还是做更多的事情?

Linux 线程同步都有哪些方法?

pthread_mutex_unlock 如何区分线程?

多线程的互斥锁的运用

未解锁锁定的互斥锁