【问题标题】:pthread_mutex_lock() only works when the return value is assigned to a variable, why?pthread_mutex_lock() 仅在将返回值分配给变量时才有效,为什么?
【发布时间】:2014-04-25 08:00:17
【问题描述】:

我正在尝试使用互斥体而不是信号量,因为我想要信号量行为但二进制(不计数)。 (也许你会注意到我正处于尝试模拟 Sleeping Barber 算法的早期阶段。)这是我的代码:

#include <stdio.h>
#include <pthread.h>

int main( int argc, char** argv ) {

  int freeSeats = 6;

  pthread_mutexattr_t mutexAttr;
  pthread_mutex_t custWaiting, wrAccess, barberReady;

  pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);

  pthread_mutex_init(&custWaiting, &mutexAttr);
  pthread_mutex_init(&wrAccess, &mutexAttr);
  pthread_mutex_init(&barberReady, &mutexAttr);

  pthread_mutex_lock(&custWaiting);
  pthread_mutex_lock(&custWaiting);
  pthread_mutex_lock(&custWaiting);

  fprintf(stdout, "got here\n\n");

  return 0;

}

当我第一次执行时,它会按预期运行(线程被阻塞,命令行挂起,而我的程序等待能够锁定)。当我杀死该程序并再次运行它时,它会打印“到这里”,这是不应该的。为什么这只会在第二次(以及所有后续)尝试时失败,而在第一次尝试时不会失败?

令人费解的是,如果我将代码修改如下(仅 init 和 lock 行):

#include <stdio.h>
#include <pthread.h>

int main( int argc, char** argv ) {

  int freeSeats = 6;

  pthread_mutexattr_t mutexAttr;
  pthread_mutex_t custWaiting, wrAccess, barberReady;

  pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);

  int y = pthread_mutex_init(&custWaiting, &mutexAttr);
  y = pthread_mutex_init(&wrAccess, &mutexAttr);
  y = pthread_mutex_init(&barberReady, &mutexAttr);

  int x = pthread_mutex_lock(&custWaiting);
  x = pthread_mutex_lock(&custWaiting);
  x = pthread_mutex_lock(&custWaiting);

  fprintf(stdout, "got here\n\n");

  return 0;

}

...然后它每次都有效。之所以如此令人抓狂,是因为我无法检查 pthread_mutex_whatever() 上的错误代码,因为当我尝试捕获错误代码时它不会失败。如果我不打算使用它们,我不想将返回值分配给ints。如您所见,我根本没有使用xy;只需将 initlock 函数的返回值分配给它们。那么为什么这会如此剧烈地改变互斥体的行为呢?还是我错过了其他东西?我做错了什么?

【问题讨论】:

    标签: c pthreads mutex


    【解决方案1】:

    你应该通过调用来初始化你的 mutexattr:

    pthread_mutexattr_init(&mutexAttr);
    

    并且还要设置类型:

    pthread_mutexattr_settype(amutexAttr, PTHREAD_MUTEX_NORMAL);
    

    否则您的代码取决于堆栈内容,而互斥锁可以是递归类型,这就是您看到随机行为的原因。如果您将类型设置为PTHREAD_MUTEX_DEFAULT,则行为未定义,而PTHREAD_MUTEX_NORMAL 会导致死锁

    【讨论】:

    • 谢谢,很棒的信息。我不知何故在文档中错过了 mutexattr 的 init 函数(我寻找它但没有发现它)。我会尝试,并尝试设置类型 NORMAL。不知道为什么,但出于某种原因,我认为使用 pthread_mutex_setpshared(...) 会涵盖 pthread_mutexattr_init(...) 必须涵盖的细节。
    • 这行得通。非常详细的答案。不幸的是,发现互斥锁不模拟二进制信号量。
    【解决方案2】:

    您对同一个互斥锁进行了三次锁定,这是未定义的行为,除非您将互斥锁声明为递归的。可能您的意思是锁定三个不同的互斥锁。

    未定义的行为意味着任何事情都可能发生,包括您在此处观察到的行为。

    要设置互斥体的属性,您必须使用pthread_mutexattr_settype 更改互斥体属性的属性。基本上有两种类型可以增强默认行为,PTHREAD_MUTEX_ERRORCHECKPTHREAD_MUTEX_RECURSIVE。如果您尝试重新锁定,第一个会阻塞,第二个可用于多次锁定和解锁。

    默认行为是未定义,因为实施此类检查的成本很高。

    【讨论】:

    • 谢谢,这是有用的信息,但也为我提出了更多问题。为了澄清,我故意多次锁定同一个互斥锁。我想强制死锁作为它是否有效的测试。我不知道那将是未定义的行为。我想我不明白为什么如果一个进程试图锁定一个已经锁定的互斥锁会导致未定义的行为(而不仅仅是进程阻塞),那么互斥锁为什么会有用。我的困惑可以理解吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多