It seems that unlocking a mutex from a thread that is different from the one where it was locked is not supported by POSIX standards, even if it seems to work in practice:
pthread_mutex_unlock unlocks the given mutex. The mutex is assumed to
be locked and owned by the calling thread on entrance to
pthread_mutex_unlock. If the mutex is of the ``fast'' kind,
pthread_mutex_unlock always returns it to the unlocked state. If it is
of the ``recursive'' kind, it decrements the locking count of the mutex
(number of pthread_mutex_lock operations performed on it by the calling
thread), and only when this count reaches zero is the mutex actually
unlocked.
On ``error checking'' mutexes, pthread_mutex_unlock actually checks at
run-time that the mutex is locked on entrance, and that it was locked
by the same thread that is now calling pthread_mutex_unlock. If these
conditions are not met, an error code is returned and the mutex remains
unchanged. ``Fast'' and ``recursive'' mutexes perform no such checks,
thus allowing a locked mutex to be unlocked by a thread other than its
owner. This is non-portable behavior and must not be relied upon.
If I actually need to do something equivalent, what is the most efficient way to do it?
For example, let's say that I have a main thread and 2 "slave" threads and that I want to activate the slave threads at some point in the main thread and wait for them to complete before continuing. Right now I am doing the following:
Main Thread:
Lock Mutex Ai
Lock Mutex Bi
Lock Mutex Af
Lock Mutex Bf
CONTINUE=true
Start Thread A
Start Thread B
...
FOR LOOP {
//Ask the slave threads to start
Unlock Mutex Ai
Unlock Mutex Bi
...
//Do some stuff while the threads are running
...
//Wait for the threads to complete
Lock Mutex Af
Lock Mutex Bf
Read Thread A result
Read Thread B result
Combine Thread A & B results
...
}
...
//Stop the threads
CONTINUE=false
Unlock Mutex Ai
Unlock Mutex Bi
Unlock Mutex Af
Unlock Mutex Bf
Wait for Thread A to terminate
Wait for Thread B to terminate
Thread A:
INFINITE LOOP {
Lock Mutex Ai
IF(CONTINUE) {
...
//Compute stuff
...
Store result
} ELSE return
Unlock Mutex Af
}
Thread B:
INFINITE LOOP {
Lock Mutex Bi
IF(CONTINUE) {
...
//Compute stuff
...
Store result
} ELSE return
Unlock Mutex Bf
}
To me it seems to be an efficient way to do parallel processing (for a particular application where the results from both slave threads need to be combined after each iteration). Is there another way that is as efficient, but POSIX-compliant, to do the same thing? My current code seems to be deadlock and race condition free, but I would not like things to break up in the case of an API change...
Thanks!
pthread_mutex_unlock unlocks the given mutex. The mutex is assumed to
be locked and owned by the calling thread on entrance to
pthread_mutex_unlock. If the mutex is of the ``fast'' kind,
pthread_mutex_unlock always returns it to the unlocked state. If it is
of the ``recursive'' kind, it decrements the locking count of the mutex
(number of pthread_mutex_lock operations performed on it by the calling
thread), and only when this count reaches zero is the mutex actually
unlocked.
On ``error checking'' mutexes, pthread_mutex_unlock actually checks at
run-time that the mutex is locked on entrance, and that it was locked
by the same thread that is now calling pthread_mutex_unlock. If these
conditions are not met, an error code is returned and the mutex remains
unchanged. ``Fast'' and ``recursive'' mutexes perform no such checks,
thus allowing a locked mutex to be unlocked by a thread other than its
owner. This is non-portable behavior and must not be relied upon.
If I actually need to do something equivalent, what is the most efficient way to do it?
For example, let's say that I have a main thread and 2 "slave" threads and that I want to activate the slave threads at some point in the main thread and wait for them to complete before continuing. Right now I am doing the following:
Main Thread:
Lock Mutex Ai
Lock Mutex Bi
Lock Mutex Af
Lock Mutex Bf
CONTINUE=true
Start Thread A
Start Thread B
...
FOR LOOP {
//Ask the slave threads to start
Unlock Mutex Ai
Unlock Mutex Bi
...
//Do some stuff while the threads are running
...
//Wait for the threads to complete
Lock Mutex Af
Lock Mutex Bf
Read Thread A result
Read Thread B result
Combine Thread A & B results
...
}
...
//Stop the threads
CONTINUE=false
Unlock Mutex Ai
Unlock Mutex Bi
Unlock Mutex Af
Unlock Mutex Bf
Wait for Thread A to terminate
Wait for Thread B to terminate
Thread A:
INFINITE LOOP {
Lock Mutex Ai
IF(CONTINUE) {
...
//Compute stuff
...
Store result
} ELSE return
Unlock Mutex Af
}
Thread B:
INFINITE LOOP {
Lock Mutex Bi
IF(CONTINUE) {
...
//Compute stuff
...
Store result
} ELSE return
Unlock Mutex Bf
}
To me it seems to be an efficient way to do parallel processing (for a particular application where the results from both slave threads need to be combined after each iteration). Is there another way that is as efficient, but POSIX-compliant, to do the same thing? My current code seems to be deadlock and race condition free, but I would not like things to break up in the case of an API change...
Thanks!