如果您解锁已经解锁的互斥锁,行为是不安全,安全还是未定义?
问题的目的与下面的代码有关,我不知道在if块中解锁互斥锁是否更好,或者只是在if块之外。
// This chunk of code makes dual locking semi-autonomous.
int c_lckd = 0, q_lckd = 0;
if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1;
if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1;
if (q_lckd && !c_lckd) { QUEUE_UNLOCK; q_lckd = 0; }
else if (c_lckd && !q_lckd) { CRUNCH_UNLOCK; c_lckd = 0; }
if (c_lckd && q_lckd) {
printf("cr = %d, max = %d, cnt = %d\n",
crunching, max_crunching, queue_count(conn_queue));
if (crunching < max_crunching && queue_count(conn_queue)) {
pthread_t tid =
pthread_create(
&tid,
NULL,
crunch_conn,
(void *)queue_dequeue(conn_queue)
);
crunching++;
}
CRUNCH_UNLOCK QUEUE_UNLOCK
}
谢谢, Chenz
答案 0 :(得分:22)
对于pthreads,它将导致未定义的行为。来自pthread_mutex_unlock的手册页:
使用调用线程未保留的互斥锁调用pthread_mutex_unlock()将导致未定义的行为。
其他互斥体将有自己的行为。正如其他人所说的那样,最好阅读手册,了解您使用的互斥锁。
答案 1 :(得分:9)
正如Glen指出的那样,如果您尝试unlock未锁定的互斥锁,则会出现未定义的行为 - 请勿尝试。调试线程很难,也不会调用未定义的行为。
更重要的是,编码风格有点不寻常 - 因为除非你同时获得两个锁,否则你不会做任何事情,因此编码:
if (pthread_mutex_trylock(&crunch_mutex) == 0)
{
if (pthread_mutex_trylock(&queue_mutex) == 0)
{
printf("cr = %d, max = %d, cnt = %d\n",
crunching, max_crunching, queue_count(conn_queue));
if (crunching < max_crunching && queue_count(conn_queue))
{
pthread_t tid;
int rc = pthread_create(&tid, NULL,
crunch_conn, (void *)queue_dequeue(conn_queue));
if (rc != 0)
{
// Error recovery
// Did you need what was returned by queue_dequeue()
// to requeue it, perhaps?
}
else
{
crunching++;
// Do something with tid here?
}
}
QUEUE_UNLOCK;
}
CRUNCH_UNLOCK;
}
这避免了'我做了'变量;很明显,只要解锁宏执行预期的操作(并且没有杂散异常或setjmps),锁定的互斥锁就会被解锁。当crunch互斥锁不可用时,它还可以避免在锁定队列互斥锁时浪费能量 - 但与增加的清晰度相比,这是一个小问题。
答案 2 :(得分:2)
一般来说,对于这样的问题,文档是最好的信息来源。不同的互斥锁可能表现不同,或者单个互斥锁上可能存在选项导致其行为不同(例如,在单个线程上递归获取互斥锁的情况下)。
答案 3 :(得分:1)
你不需要这样做。试试这个:
// This chunk of code makes dual locking semi-autonomous.
int c_lckd = 0, q_lckd = 0;
if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1;
if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1;
if (c_lckd && q_lckd) {
printf("cr = %d, max = %d, cnt = %d\n",
crunching, max_crunching, queue_count(conn_queue));
if (crunching < max_crunching && queue_count(conn_queue)) {
pthread_t tid =
pthread_create(
&tid,
NULL,
crunch_conn,
(void *)queue_dequeue(conn_queue)
);
crunching++;
}
}
if (q_lckd) { QUEUE_UNLOCK; q_lckd = 0; }
if (c_lckd) { CRUNCH_UNLOCK; c_lckd = 0; }
它更容易理解,并且不会冒险尝试解锁未锁定的互斥锁。
答案 4 :(得分:0)
只有在同一个线程中先前锁定了相同的互斥锁时,才应在线程中完成互斥锁解锁。根据手册页,所有其他案例都是未定义的。
如果互斥锁类型为PTHREAD_MUTEX_DEFAULT,则尝试递归 锁定互斥锁导致未定义的行为。试图解锁 互斥锁如果没有被调用线程锁定导致 未定义的行为。如果不是,则尝试解锁互斥锁 锁定导致未定义的行为。
答案 5 :(得分:0)
试试吧。这是正确的代码。
// Mutex is not busy
if(pthread_mutex_trylock(&object->mtx) == 0) {
if(pthread_mutex_unlock(&object->mtx)!=0) {
perror("ERRN: pthread_mutex_unlock:");
}
}
// Mutex is already busy
else {
if(pthread_mutex_unlock(&object->mtx)!=0) {
perror("ERRN: pthread_mutex_unlock:");
}
}
// 在这一点上 - 我们正确地解锁了互斥锁。
if(pthread_mutex_destroy(&object->mtx) != 0) {
perror("ERRN: pthread_mutex_destroy:");
}