【问题标题】:threads behaviour on multiple locks of the same mutex同一互斥锁的多个锁上的线程行为
【发布时间】:2011-06-06 15:27:28
【问题描述】:

如果我在函数的两个不同位置锁定同一个互斥锁,当一个线程在其中一个线程中发生上下文切换,而第二个线程到达另一个线程时,它会被阻塞吗?

我会试着举一个简单的例子来说明我的意思,也许它会更清楚。 假设我在文件 test.c 中有以下代码

int globalVar = 0;    

void testMutex(pthread_mutex_t myMutex) {
    pthread_mutex_lock(&myMutex);
    globalVar++;
    pthread_mutex_unlock(&myMutex);

    printf("%s \n", "Doing some other stuff here");

    pthread_mutex_lock(&myMutex);
    globalVar--;
    pthread_mutex_unlock(&myMutex);
}

在另一个文件 main.c 中,我有一个 main 函数,它创建两个线程,thread1thread2,都运行 testMutex 函数。 thread1首先执行,而在函数的第二部分(--部分,在printf之后),在互斥锁解锁之前,thread2开始运行,从函数开始。 thread2 是否能够执行 globalVar++,还是会一直处于阻塞状态,等待互斥锁被解锁?

提前致谢!

【问题讨论】:

    标签: c pthreads mutex


    【解决方案1】:

    简短的回答是“是”。

    pthread_mutex_lock documentation 说明了这一点:

    mutex 引用的 mutex 对象应通过调用 pthread_mutex_lock() 来锁定。如果互斥锁已被锁定,则调用线程应阻塞,直到互斥锁可用。该操作将返回互斥对象所引用的互斥对象,该互斥对象处于锁定状态,调用线程为其所有者。

    换句话说,在从pthread_mutex_lock 返回时,互斥锁由线程“拥有”。系统保证在任何时候最多有一个线程可以“拥有”一个互斥锁。

    【讨论】:

      【解决方案2】:

      首先,您不应该通过值传递pthread_mutex_t

      void testMutex(pthread_mutex_t myMutex)
      

      使pthread_mutex_t*。尽管您的代码可能对您有用(我对此表示怀疑),但它不可移植,因为 pthreads 类型本来就是不透明的。

      There's a discussion of this in the relevant FAQ。除其他外,它暗示您使用pthread_mutex_t 可能会导致每次调用testMutex 时都会生成互斥锁的副本(该函数锁定副本而不是原始互斥体)。

      修复此问题后,以下内容将成立:

      由于两个线程使用相同的互斥体,只要第一个线程位于两个 pthread_mutex_lock-pthread_mutex_unlock 部分中的任何一个内,第二个线程就会调用两个 pthread_mutex_lock 中的任何一个。反之亦然(只要第二个线程有互斥锁,第一个线程就会阻塞)。

      换句话说,只要一个线程锁定了一个互斥体,就没有其他线程可以锁定同一个互斥体。

      【讨论】:

      • 我不认为有任何实现可以使用此代码。相反,pthread_mutex_lock 将锁定 一个 互斥体的副本,这不会阻塞其他线程。从技术上讲,对互斥体的副本执行任何操作都会导致 UB,但这种行为几乎可以肯定就像我刚刚针对实际实现所描述的那样。
      • 实际上您链接的FAQ中的文字是错误的。与它所说的相反,复制pthread_t 是完全有效的,事实上,标准函数中pthread_t 的所有使用都通过值(即使它是一个结构)而不是通过引用传递它,除了pthread_create,其中一个存储结果的地址被传递。当然pthread_t本身通常是一个指向不透明数据结构的指针...
      【解决方案3】:

      thread2 将阻塞在 pthread_mutex_lock() 函数中,直到 thread1 解锁互斥锁。

      如果不是,那么互斥锁的最初用途是什么?

      【讨论】:

        【解决方案4】:

        thread2 将保持阻塞状态,并且在 thread1 释放互斥体之前无法递增 globalVarr++。

        【讨论】:

          【解决方案5】:

          函数中的位置并不重要——如果一个线程有互斥体,另一个线程就不能得到它。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-02-14
            • 2021-02-19
            • 1970-01-01
            • 1970-01-01
            • 2014-05-02
            • 1970-01-01
            • 2012-11-28
            • 2012-12-25
            相关资源
            最近更新 更多