问题
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 !
回答1:
This is not what I see... Notice that EPERM is what T2 should return, not T1. And dually, EDEADLK is what T1 should return if you lock the same mutex twice recursively.
This is the code I used to test:
#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);
}
回答2:
POSIX manual page for pthread_mutexattr_setpshared(3)
says:
The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a mutex to be operated upon by any thread that has access to the memory where the mutex is allocated, even if the mutex is allocated in memory that is shared by multiple processes. If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, the mutex shall only be operated upon by threads created within the same process as the thread that initialized the mutex; if threads of differing processes attempt to operate on such a mutex, the behavior is undefined. The default value of the attribute shall be PTHREAD_PROCESS_PRIVATE.
The purpose of the attribute is only to allow different processes (by means of shared memory) to access the same pthread_mutex_t
object. No change of actual synchronization semantics is implied. And when you think about it, what would be the purpose of a synchronization primitive (pthread_mutex_t
object) if every thread could just lock and unlock it whoever comes first. Such an anarchy hardly has a place in multi-threaded program design!
来源:https://stackoverflow.com/questions/17720048/pthread-mutex-unlocking-over-different-threads