multithreading 如果您解锁一个已经解锁的互斥锁,行为是否未定义?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1778780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 01:05:36  来源:igfitidea点击:

If you unlock an already unlocked mutex, is the behavior undefined?

multithreadingmutex

提问by Crazy Chenz

If you unlock an already unlocked mutex, is the behavior unsafe, safe, or undefined?

如果解锁一个已经解锁的互斥锁,行为是不安全的、安全的还是未定义的?

The purpose of the question is related to the following code, where I don't know if it would be better to unlock the mutexes within the if block, or just outside the if block.

问题的目的与以下代码有关,我不知道在 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
    }

Thanks, Chenz

谢谢,陈兹

采纳答案by Glen

For pthreads it will result in undefined behaviour. From the man page for pthread_mutex_unlock:

对于 pthreads,它将导致未定义的行为。从pthread_mutex_unlock的手册页:

Calling pthread_mutex_unlock() with a mutex that the calling thread does not hold will result in undefined behavior.

使用调用线程不持有的互斥量调用 pthread_mutex_unlock() 将导致未定义的行为。

Other mutexes will have their own behviour. As others have stated, it's best to read the manual for whichever mutex you're using.

其他互斥体将有自己的行为。正如其他人所说,最好阅读您正在使用的互斥锁的手册。

回答by Jonathan Leffler

As Glen noted, you get undefined behaviour if you attempt to unlockan unlocked mutex - don't try it. Debugging threads is hard enough without invoking undefined behaviour too.

正如格伦所指出的,如果您尝试解锁未锁定的互斥锁,则会出现未定义的行为- 不要尝试。在不调用未定义行为的情况下调试线程已经足够困难了。

More importantly, the coding style is a little unusual - since you aren't going to do anything unless you get both locks, code accordingly:

更重要的是,编码风格有点不寻常 - 因为除非你得到两个锁,否则你不会做任何事情,相应地编码:

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;
}

This avoids the 'did I do it' variables; it is also instantly clear that as long as the unlock macros do what is expected (and there are no stray exceptions or setjmps around), that the mutexes that are locked are unlocked. It also avoids wasting energy on locking the queue mutex when the crunch mutex isn't available - but that's a minor issue compared to the added clarity.

这避免了“我做了吗”变量;也很明显,只要解锁宏执行预期的操作(并且周围没有杂散异常或 setjmps),被锁定的互斥锁就会被解锁。当紧缩互斥锁不可用时,它还避免了在锁定队列互斥锁上浪费精力 - 但与增加的清晰度相比,这是一个小问题。

回答by Greg D

In general, for questions like this, the documentation is the best source of information. Different mutexes may behave differently, or there may be options on a single mutex which cause it to behave different (such as in the case of recursively acquiring a mutex on a single thread).

一般来说,对于此类问题,文档是最好的信息来源。不同的互斥体的行为可能不同,或者单个互斥体上可能存在导致其行为不同的选项(例如在单个线程上递归获取互斥体的情况)。

回答by Michael Kohne

You don't need to do it that way. Try this:

你不需要那样做。尝试这个:

    // 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; }

It's a little easier to follow and doesn't risk trying to unlock an unlocked mutex.

它更容易遵循,并且不会冒险尝试解锁未锁定的互斥锁。

回答by rashok

A mutex unlock should be done in a thread only if the same mutex is locked earlier in the same thread. All other cases are undefined behviour as per man page.

仅当同一互斥锁在同一线程中较早锁定时,才应在线程中完成互斥锁解锁。根据手册页,所有其他情况都是未定义的行为。

If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex results in undefined behaviour. Attempting to unlock the mutex if it was not locked by the calling thread results in undefined behaviour. Attempting to unlock the mutex if it is not locked results in undefined behaviour.

如果互斥类型为 PTHREAD_MUTEX_DEFAULT,则尝试递归锁定互斥会导致未定义的行为。如果互斥锁未被调用线程锁定,则尝试解锁它会导致未定义的行为。如果互斥锁未锁定,则尝试解锁它会导致未定义的行为。

回答by stacker

Try it. This is code working correct.

尝试一下。这是工作正常的代码。

// 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:");
    }
}

// In this point -- we correctly unlocked mutex.

//在这一点上——我们正确地解锁了互斥锁。

if(pthread_mutex_destroy(&object->mtx) != 0) {
    perror("ERRN: pthread_mutex_destroy:");
}