pthread互斥锁(un)锁定不同的线程

时间:2013-07-18 09:49:33

标签: multithreading process pthreads mutex shared

我有一个进程,其中main初始化一个互斥锁调用:

MutexInit( pthread_mutex_t *Mutex )
{
    pthread_mutexattr_t mattr;

    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK_NP);

    #ifndef _POSIX_THREAD_PROCESS_SHARED
    #error "This platform does not support process shared mutex!"
    #else
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    #endif

    pthread_mutex_init( Mutex, &mattr );
}

main最初锁定互斥锁M1然后创建线程T1和T2。

T1启动并完成一些工作。 T2启动并执行其他操作,并在某个时刻锁定该互斥锁M1。由于互斥锁类型为PTHREAD_MUTEX_ERRORCHECK_NP T2未被阻止,而是返回错误EDEADLK,表示互斥锁M1已被锁定。所以T2继续试图锁定。到目前为止一切都很好。

然后T1到达解锁M1的程度,但返回错误EPERM,说T1不拥有互斥锁!所以T2永远不会被解锁。

如果我从MutexInit删除设置属性:

pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK_NP);

#ifndef _POSIX_THREAD_PROCESS_SHARED
#error "This platform does not support process shared mutex!"
#else
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
#endif

并致电pthread_mutex_init( Mutex, NULL );,即。默认属性,一切正常!

我确实需要初始的MutexInit例程,因为我们还使用了互斥进程(通过共享内存)。

有人有任何想法吗?我读了很多文章和帖子,所以任何帮助都会受到关注。

修改: 使用修改版的Paolo代码来证明我的观察结果:

这是Paolo代码的修改版本,以适应“我的测序”:

#include <stddef.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <semaphore.h>

pthread_mutex_t m;
sem_t s1, s2;

void print(const char *s, int err)
{
    printf("%s %d %s\n", s, err, strerror(err));
}

void *start_t1(void *arg)
{
    sem_wait(&s1); // <-t2
    print("t1: unlock ", pthread_mutex_unlock(&m));
    sem_post(&s2); //->t2
}

void *start_t2(void *arg)
{
    sem_wait(&s2); // <-main
    print("t2: lock ", pthread_mutex_lock(&m));
    sem_post(&s1); // ->t1

    sem_wait(&s2); // <-t1
    sem_post(&s1); // ->main
}

void main(void)
{
    pthread_mutexattr_t mattr;
    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);

    sem_init(&s1, 0, 0);
    sem_init(&s2, 0, 0);

    print("main init", pthread_mutex_init(&m, &mattr));

    pthread_t t2, t1;
    pthread_create(&t1, NULL, start_t1, NULL);
    pthread_create(&t2, NULL, start_t2, NULL);

    sem_post(&s2); // ->t2
    sem_wait(&s1); // <-t2

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}

输出结果为:

main init 0 Success
t2: lock  0 Success
t1: unlock  1 Operation not permitted

由于类型PTHREAD_PROCESS_SHARED,我希望允许T1解锁互斥锁。我错了吗?

如果互斥锁初始化更改为默认值(pthread_mutex_init(&m, **NULL**)),那么它正在工作。

main init 0 Success
t2: lock  0 Success
t1: unlock  0 Success

似乎是某种倒置的逻辑!

2 个答案:

答案 0 :(得分:2)

pthread_mutexattr_setpshared(3)的POSIX手册页说:

  

进程共享属性设置为 PTHREAD_PROCESS_SHARED ,以允许任何可以访问分配了互斥锁的内存的线程对互斥锁进行操作,甚至如果互斥锁分配在由多个进程共享的内存中。如果进程共享属性为 PTHREAD_PROCESS_PRIVATE ,则只应在与初始化互斥锁的线程相同的进程中创建的线程上操作互斥锁;如果不同进程的线程试图在这样的互斥锁上运行,则行为是未定义的。属性的默认值应为 PTHREAD_PROCESS_PRIVATE

该属性的目的只是允许不同的进程(通过共享内存)访问同一个pthread_mutex_t对象。不暗示实际同步语义的变化。当你考虑它的时候,如果每个线程只能锁定和解锁它,那么同步原语(pthread_mutex_t对象)的目的是什么。这种无政府状态几乎没有在多线程程序设计中占有一席之地!

答案 1 :(得分:1)

这不是我所看到的......请注意,EPERM是T2应该返回的,而不是T1。而且,如果你以递归方式锁定相同的互斥锁,那么EDEADLK就是T1应该返回的内容。

这是我用来测试的代码:

#include <stddef.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <semaphore.h>

pthread_mutex_t m;
sem_t s1, s2;

void print(const char *s, int err)
{
    printf("%s %d %s\n", s, err, strerror(err));
}

void *start_t2(void *arg)
{
    print("t2", pthread_mutex_unlock(&m));
    sem_post(&s1);
    sem_wait(&s2);
}

void main(void)
{
    pthread_mutexattr_t mattr;
    pthread_mutexattr_init(&mattr);
    pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&m, &mattr);

    sem_init(&s1, 0, 0);
    sem_init(&s2, 0, 0);

    print("t1", pthread_mutex_lock(&m));

    pthread_t t2;
    pthread_create(&t2, NULL, start_t2, NULL);

    sem_wait(&s1);
    print("t1", pthread_mutex_unlock(&m));
    sem_post(&s2);
    pthread_join(t2, NULL);
}