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

时间:2009-11-22 13:59:37

标签: multithreading mutex

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

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

6 个答案:

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