Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 递归还是错误检查互斥?_C_Pthreads_Posix_Mutex - Fatal编程技术网

C 递归还是错误检查互斥?

C 递归还是错误检查互斥?,c,pthreads,posix,mutex,C,Pthreads,Posix,Mutex,直到最近,我还认为错误检查互斥体主要是一种调试工具,在正确的代码中几乎没有价值,但后来我意识到它们具有可以替换递归互斥体的特性,如: void foo() { int ok_to_unlock = !pthread_mutex_lock(m); /* do something */ if (ok_to_unlock) pthread_mutex_unlock(m); } 请注意,pthread\u mutex\u lock在成功时返回0,如果调用方已经持有锁,EDEAD

直到最近,我还认为错误检查互斥体主要是一种调试工具,在正确的代码中几乎没有价值,但后来我意识到它们具有可以替换递归互斥体的特性,如:

void foo()
{
    int ok_to_unlock = !pthread_mutex_lock(m);
    /* do something */
    if (ok_to_unlock) pthread_mutex_unlock(m);
}
请注意,
pthread\u mutex\u lock
在成功时返回0,如果调用方已经持有锁,
EDEADLK
。这种用法的优点是,您不必担心超过任意递归锁限制;“锁计数”隐含在调用帧中。原则上,这个习惯用法的性能也可能稍好一些,因为调用线程已经持有锁时,永远不会调用
pthread\u mutex\u unlock


然后,我的问题主要是关于样式:像这样使用错误检查互斥是否会降低代码的清晰度?您不想这样使用它们还有其他原因吗?

这是主观的,但我觉得这会使代码不那么清晰。

我认为您可能意识到的任何性能改进都会被使用错误检查互斥锁的成本所淹没。然而,即使这些成本也可能很小,我看不出有任何理由不使用这个成语。我唯一的建议是使用变量名,比如
locked
,而不是
ok\u来解锁

请注意,
pthread\u mutex\u lock
成功返回
0
EDEADLK
,如果调用方已经持有锁

您发布的代码并不完全健壮,因为
EDEADLK
不是唯一可能返回的错误。如果互斥锁未正确初始化,也会出现
EINVAL


大卫·布滕霍夫(David Butenhof)有一些关于递归互斥的使用,这听起来很主观我想;最后一句中的问题有点非主观化(非风格原因,这种用法不好)。除了风格之外,我还要研究PTHREAD_MUTEX_ERRORCHECK的性能。如果保存一些pthread_mutex_xxx调用,如果结果表明错误检查互斥比正常或递归互斥慢10倍,则可能不值得。原则上,错误检查和递归互斥所涉及的工作量是相同的。两者都必须识别调用线程,并将其与保存在互斥体中的所有者进行比较。区别只在于它们在两个匹配时的行为方式(增加计数器或返回错误)。“locked”的问题是互斥锁以任何方式被锁定-变量表示谁有责任解锁它(我们或调用者)。不管你怎么称呼它,如果互斥锁在我们出现之前没有被锁定,那么这个变量是真的,如果它已经被锁定,那么这个变量是假的。同意——未来的维护者可能会问为什么程序中的锁会返回“错误”,更不用说,任何用于检查并发程序正确性的工具都可能会遇到问题。使用未初始化的互斥会导致UB,因此不需要考虑这种情况。链接为+1。一段有趣的历史。我曾经同意这种观点,直到我了解stdio锁定和
flockfile
是如何工作的,这是一种递归互斥。然后我意识到递归互斥允许您保护最小的数据操作单元,同时还允许调用者将更大的数据操作单元设置为原子单元—在stdio的情况下,确保多个文件IO操作作为一个原子单元进行。