3

I have a process where main initializes a mutex calling:

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 is initially locking mutex M1 and creates then threads T1 and T2.

T1 is started and does some work. T2 is started and does something else and at some point doing a lock on that mutex M1. Since mutex type is PTHREAD_MUTEX_ERRORCHECK_NP T2 is not blocked, instead error EDEADLK is returned, indicating that the mutex M1 is already locked. So T2 continues trying to lock. That's fine so far.

Then T1 comes to the point where it unlocks M1, but error EPERM is returned, saying, that T1 does not own the mutex !? So T2 never gets unlocked.

If I remove setting the attributes from 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

and calling pthread_mutex_init( Mutex, NULL );, ie. default attributes, everything is working fine !

I do need the initial MutexInit routine, because we're also using mutexes over processes (via shared memory).

Does anybody have any idea ? I've read so many articles and posts, so any help will be appriciated.

EDIT: Using a modified version of Paolo's code to demonstrate my observation:

This a the modified version of Paolo's code to fit "my sequencing":

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

The output is:

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

I would expect T1 to be allowed to unlock the mutex because of type PTHREAD_PROCESS_SHARED. Am I wrong ?

If the mutex initialization is changed to defaults (pthread_mutex_init(&m, **NULL**)), then it's working.

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

Seems to be some kind of inverted logic !

4

2 回答 2

2

POSIX手册页pthread_mutexattr_setpshared(3)说:

process-shared属性设置为PTHREAD_PROCESS_SHARED以允许任何有权访问分配互斥锁的内存的线程对 互斥锁进行操作,即使互斥锁是在由多个进程共享的内存中分配的。如果进程共享属性是PTHREAD_PROCESS_PRIVATE,则互斥锁只能由与初始化互斥锁的线程在同一进程中创建的线程操作;如果不同进程的线程试图对这样的互斥体进行操作,则行为未定义。该属性的默认值应为PTHREAD_PROCESS_PRIVATE

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

于 2013-07-30T03:23:35.173 回答
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);
}
于 2013-07-18T13:01:31.817 回答