Pthread:在非所有者线程中锁定PTHREAD_MUTEX_ERRORCHECK互斥锁

3

经典问题,请问我在运行以下代码时,我没有从代码中找到确认。这是C语言的代码,我正在Windows系统上运行。

/* This is an implementation of the threads API of POSIX 1003.1-2001.*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
//equivalent to PTHREAD_MUTEX_ERRORCHECK

void* thread_function(void *args)
{
    int rc;
    rc = pthread_mutex_unlock( & mutex );
    printf( "[thread_function] pthread_mutex_unlock rc: %d \n", rc);
    return 0;
}

int main(int argc, char* argv[])
{
    int rc;
    pthread_t id;

    pthread_mutex_lock( &mutex );
    rc =  pthread_create(&id, NULL, thread_function, NULL);
    pthread_join(id, NULL);

    printf( "[main] completed\n");
}

rc = pthread_mutex_unlock( & mutex ); - 返回的 rc 值等于 1,这是预期的结果。

但当我将代码更改为 rc = pthread_mutex_lock( & mutex ); 时,错误就不会发生。 但在许多 Pthread API 文档中都提到: “如果互斥体类型为 PTHREAD_MUTEX_ERRORCHECK,则应提供错误检查。如果线程尝试重新锁定已经锁定的互斥体,则会返回错误

但对我来说并没有返回错误,问题是为什么? 我唯一猜测的是它取决于我正在使用的 PThread 实现。 它也可能取决于操作系统;即相同的代码和相同版本的 Pthread 库在 Linux 上会产生不同的结果。

请问有人能澄清吗?

谢谢!


你为什么会期望 pthread_mutex_lock(&mutex); 返回一个错误呢?在你展示的上下文中,这是一个有效的调用。 - alk
3个回答

2

当一个线程试图锁定另一个线程已经锁定的互斥量时,它会阻塞。这当然是整个目的:如果它是一个错误,那么它将是无用的。错误检查是针对那些可能尝试锁定已经锁定互斥量的线程的程序。这通常是由逻辑错误引起的,尽管可以使用它模拟递归互斥量或可能将互斥量的锁定状态用作某种形式的内存。


0
在Posix规范中的一个错误是“默认”互斥类型的概念 - 这取决于实现。这意味着“默认”互斥的语义是任何人的猜测。混淆?当然。
我的建议是,如果您关心可移植性,请永远不要使用“默认”作为互斥类型。

0
通常情况下,当您在同一线程中尝试第二次锁定互斥量(默认类型)时,您的代码将被阻止。为了防止这种阻塞情况,使用错误检查互斥量。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>

#define IN_MAIN     ""
#define IN_THREAD   "\t"
#define START_MAIN  printf(IN_MAIN "\n-- Main Start -- \n");
#define END_MAIN    printf(IN_MAIN "-- Main End -- \n\n");  \
                    exit(EXIT_SUCCESS);

#define ERROR_HANDLER(en, msg) \
                do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void * thread_routine(void * arg)
{
    printf(IN_THREAD "-- Thread Start -- \n");
    int ret;

    pthread_mutex_lock(&mutex);
    printf(IN_THREAD " Thread acquire lock for first time \n");

    ret = pthread_mutex_lock(&mutex);
    if(ret)
    {
        switch(ret)
        {
            case EDEADLK:
                printf(IN_THREAD " A deadlock condition was detected \n");
                break;

            default:
                ERROR_HANDLER(ret, "pthread_mutex_lock");
        }
    }

    sleep(1);
    ret = pthread_mutex_unlock(&mutex);
    printf(IN_THREAD " Thread release lock first time -- %d \n", ret);

    sleep(1);
    ret = pthread_mutex_unlock(&mutex);
    printf(IN_THREAD " Thread release lock second time -- %d \n", ret);
    printf(IN_THREAD "-- Thread End --\n");
    pthread_exit(NULL);
}

int main(int argc, char ** argv)
{
    START_MAIN;
    pthread_t thread_id;
    pthread_mutexattr_t mutex_attr;
    int mutex_type, ret=0;

    pthread_mutexattr_init(&mutex_attr);
    ret = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
    if(ret)
        ERROR_HANDLER(ret, "pthread_mutexattr_settype");

    pthread_mutex_init(&mutex, &mutex_attr);
    pthread_create(&thread_id, NULL, thread_routine, NULL);
    pthread_join(thread_id, NULL);
    END_MAIN;
}

考虑上面的例子,当您执行上述代码时,它会打印“检测到死锁条件”。这是因为互斥类型是错误检查。现在注释掉该行。
ret = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);

执行代码。您会注意到在打印“线程第一次获取锁”后,您的代码被阻塞。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接