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

时间:2018-01-27 06:44:50

标签: c pthreads

请提出经典问题; 我没有从代码中找到确认; 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 lib将在Linux上提供不同的结果。

有人可以澄清一下吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

当一个线程试图锁定另一个线程锁定的互斥锁时,它会阻止。这当然是重点:如果是错误就没用了。错误检查适用于线程可能尝试锁定互斥锁 已锁定的程序。这通常是由逻辑错误引起的,虽然可以使用它来模拟递归互斥锁,或者可能使用互斥锁的锁定状态作为某种内存。

答案 1 :(得分: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);

并执行代码。您会在代码显示“首次获取线程锁定”后发现代码被阻止。

答案 2 :(得分:0)

Posix 规范中的一个错误是“默认”互斥类型的概念——它依赖于实现。意思是“默认”互斥锁的语义是任何人猜测的。令人困惑?你打赌。

如果您完全关心可移植性,我的建议是永远不要对互斥类型使用“默认”。