【问题标题】:Check to see if a pthread mutex is locked or unlocked (After a thread has locked itself)检查 pthread 互斥锁是否被锁定或解锁(在线程锁定自身之后)
【发布时间】:2011-05-20 17:35:49
【问题描述】:

我需要在 if 语句中查看互斥锁是否被锁定或解锁,所以我像这样检查它...

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

但是当我检查它时,gcc 给了我以下错误:

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

那么如何检查互斥体是否被锁定?

编辑:

我的问题的一个关键组成部分是我的线程(按设计)在将控制权传递给另一个线程之后立即锁定自己。所以当线程 A 将控制权交给线程 B 时,线程 A 被锁定,线程 B 做一些事情,然后当线程 B 完成后,它会解锁线程 A。

这样做的问题是,如果线程 B 尝试解锁线程 A,而线程 A 尚未完成自身锁定,则解锁调用将丢失,线程 A 仍处于锁定状态,从而导致死锁。

更新:

我根据 caf 的建议重新制作了我的程序,但我仍然遇到问题。我已尽我所能将我的程序融入到结构 caf 中,但我什至无法说出现在导致死锁的原因...我创建了一个新问题 here 寻求有关我的代码的帮助。

以下是 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);
    }
}

【问题讨论】:

  • 快速说明,互斥锁必须由锁定它们的线程解锁。如果您想要一个可以由一个线程锁定并由另一个线程解锁的锁定结构,则必须使用信号量(或构建您自己的信号量,如上例所示)。如果一个线程锁定一个 mutx 而另一个线程释放它,就会出现非常丑陋的同步错误

标签: c pthreads deadlock mutex


【解决方案1】:

您可以使用pthread_mutex_trylock。如果成功,则互斥体无人认领,您现在拥有它(因此您应该释放它并在您的情况下返回“未持有”)。否则,有人拿着它。

我必须强调,尽管“检查互斥锁是否无人认领”是一个非常糟糕的主意。这种思维有内在的竞争条件。如果这样的函数在时间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...
}

【讨论】:

  • @asveikau 我的问题是我有一个线程 (a) 将控制权传递给另一个线程 (b) 然后锁定自身。一旦线程b 完成,它会解锁线程a 然后锁定自己。系统运行良好,但在极少数情况下线程b“解锁”线程a 之前线程a 锁定自身,因此“解锁”丢失并且程序死锁。我尝试使用trylock,但不是您建议的方式...我会再试一次。
  • @typoknig - 听起来你应该考虑一个更简单的同步方案。例如,您可以让 B 发出 A 等待的信号量。
  • @asveikau 问题是线程 A 有控制权并且必须锁定自己,我无法控制它锁定自己的速度。 B 确实为线程 A 发出信号/解锁信号量,当线程 B 完成时,但如果线程 A 尚未锁定自身(并且在线程 B 发出解锁信号后这样做),则线程 A 将保持锁定状态。
  • 线程不能共享一个互斥体是否有原因?线程 A 释放互斥体,让出 CPU,然后再次等待互斥体。线程 B 会在 A 释放的时候被唤醒,然后取 mutex,就没有 notify-before-wait 的问题了。
  • 我有很多线程和(如 A[10] 和 B[10]),它们没有配对在一起,但相互依赖。例如线程 A[1] 可能依赖于线程 B[5] 这个循环,但下一个循环它可能依赖于线程 B[7] 或其他线程。
【解决方案2】:

互斥锁不是您要实现的方案的正确原语。您应该使用条件变量

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(),直到另一个线程发出信号唤醒它。这不会死锁。

通过为每个线程分配一个intpthread_cond_tpthread_mutex_t,它可以轻松扩展到多个线程。

【讨论】:

  • @caf 我最初尝试使用条件,但我的线程需要同时运行,除非我想为每个线程创建一个条件(一组条件不起作用,因为它会被阻塞每次它被任何线程访问,从而消除了所需的并发性)我不知道如何使这项工作。
  • @typoknig:一系列条件正是您所需要的。它不会“每次被任何线程访问时都被阻塞”。每个条件变量都是独立的 - 将它们保存在数组中还是单独命名的全局变量中都没有关系。
  • @caf 我已经更新了我的问题并添加了我的代码,也许你可以看看它。我知道您建议的结构是正确的,但我仍然无法使其正常工作(请参阅更新的问题)。我发布的代码是从我提出问题时完全重写的(现在使用条件)。
  • @typoknig:我会看看,但您最好将新代码作为新问题发布。
  • @caf 我按照你的建议提出了一个新问题,谢谢你的帮助。
【解决方案3】:

您无法将 pthread_mutex_t 与 int 进行比较。

你可以使用

int pthread_mutex_trylock(pthread_mutex_t *mutex);

检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 2021-12-23
    相关资源
    最近更新 更多