The ACE Library provides two classes for thread synchronization: ACE_Thread_Mutex and ACE_REcursive_Thread_Mutex. In my opinion, we can use ACE_REcursive_Thread_Mutex instead of ACE_Thread_Mutex for Thread Synchronization in linux. The reason is simple, because ACE_Thread_Mutex does not support thread re-entry. Once reentrant (the same thread calls ACE_Thread_Mutex: acquire twice), the thread will be deadlocked.
To clarify this problem, we need to understand how the operating system implements thread locks. In Windows, CRITICAL_SECTION is simple. CRITICAL_SECTION supports re-entry. Therefore, ACE_Thread_Mutex or ACE_REcursive_Thread_Mutex are the same for threads in Windows. In linux, the posix thread library is used for implementation. The mutex of pthread is divided into three types: fast, recursive, and error checking. When the thread calls pthread_mutex_lock, if the thread re-enters the lock, then:
The "fast" lock suspends the current thread.
The "resursive" lock succeeds and immediately returns the number of times it is locked.
The "error checking" lock immediately returns EDEADLK
Obviously, ACE_Thread_Mutex is implemented in fast mode.
I have experience in developing C ++ multi-threaded programs on multiple platforms (Windows, AIX, Solaris, hp-ux, Linux, but I have never figured out what is the use of a non-reentrant thread lock. It is too inconvenient to use such a lock. Please be careful, and a deadlock will occur if you are not careful. Therefore, you usually need to manually write code to encapsulate it into a reentrant lock. ACE also provides such an encapsulation that is implemented using mutex and cond. The Code is as follows:
ACE_ OS: recursive_mutex_lock (ACE_recursive_thread_mutex_t * m)
{
# If defined (ACE_HAS_THREADS)
# If defined (ACE_HAS_RECURSIVE_MUTEXES)
Return ACE_ OS: thread_mutex_lock (m );
# Else
ACE_thread_t t_id = ACE_ OS: thr_self ();
Int result = 0;
// Acquire the guard.
If (ACE_ OS: thread_mutex_lock (& m-> nesting_mutex _) =-1)
Result =-1;
Else
{
// If there's no contention, just grab the lock immediately
// (Since this is the common case we'll optimize for it ).
If (m-> nesting_level _ = 0)
M-> owner_id _ = t_id;
// If we already own the lock, then increment the nesting level
// And return.
Else if (ACE_ OS: thr_equal (t_id, m-> owner_id _) = 0)
{
// Wait until the nesting level has dropped to zero,
// Which point we can acquire the lock.
While (m-> nesting_level _> 0)
ACE_ OS: cond_wait (& m-> lock_available _,
& M-> nesting_mutex _);
// At this point the nesting_mutex _ is held...
M-> owner_id _ = t_id;
}
// At this point, we can safely increment the nesting_level _ no
// Matter how we got here!
M-> nesting_level _ ++;
}
{
// Save/restore errno.
ACE_Errno_Guard error (errno );
ACE_ OS: thread_mutex_unlock (& m-> nesting_mutex _);
}
Return result;
# Endif/* ACE_HAS_RECURSIVE_MUTEXES */
# Else
ACE_UNUSED_ARG (m );
ACE_NOTSUP_RETURN (-1 );
# Endif/* ACE_HAS_THREADS */
}
This encapsulation is used on platforms where the posix thread library does not support recursive mutex. If posix thread supports recursive, you can use pthread_mutex_lock directly. So my conclusion is: In the ACE environment, we directly use ACE_REcursive_Thread_Mutex and forget the existence of ACE_Thread_Mutex.