I was wondering if I could make a recursive mutex type on my own with a PTHREAD_MUTEX_ERRORCHECK
mutex, this is the result:
typedef struct {
pthread_mutex_t mutex;
uint32_t deadlocks;
} pthread_recursivemutex_t;
int pthread_recursivemutex_init(pthread_recursivemutex_t *mutex)
{
int ret;
pthread_mutexattr_t attr;
mutex->deadlocks = 0;
ret = pthread_mutexattr_init(&attr);
if (ret != 0) {
return ret;
}
(void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
ret = pthread_mutex_init(&mutex->mutex, &attr);
(void)pthread_mutexattr_destroy(&attr);
return ret;
}
void pthread_recursivemutex_lock(pthread_recursivemutex_t *mutex)
{
int ret;
ret = pthread_mutex_lock(&mutex->mutex);
if (ret == 0) {
mutex->deadlocks = 0;
} else if (ret == EDEADLK) {
mutex->deadlocks += 1;
}
}
void pthread_recursivemutex_unlock(pthread_recursivemutex_t *mutex)
{
if (mutex->deadlocks == 0) {
(void)pthread_mutex_unlock(&mutex->mutex);
} else {
mutex->deadlocks -= 1;
}
}
void pthread_recursivemutex_destroy(pthread_recursivemutex_t *mutex)
{
(void)pthread_mutex_destroy(&mutex->mutex);
}
I found out that this type of recursive mutex is a lot faster than a mutex with the PTHREAD_MUTEX_RECURSIVE
attribute:
iterations : 1000000
pthread_mutex_t : 71757 μSeconds
pthread_recursivemutex_t : 48583 μSeconds
Test code (each called 1000000 times):
void mutex_test()
{
pthread_mutex_lock(&recursiveMutex);
pthread_mutex_lock(&recursiveMutex);
pthread_mutex_unlock(&recursiveMutex);
pthread_mutex_unlock(&recursiveMutex);
}
void recursivemutex_test()
{
pthread_recursivemutex_lock(&myMutex);
pthread_recursivemutex_lock(&myMutex);
pthread_recursivemutex_unlock(&myMutex);
pthread_recursivemutex_unlock(&myMutex);
}
pthread_recursivemutex_t
is almost twice as fast as pthread_mutex_t
?! But both behave the same way...?
BTW:
pthread_mutex_t my_mutex;
void *m(void*a)
{
printf("m: %d %d\n", pthread_mutex_lock(&my_mutex), EDEADLK);
usleep(500 * 1000);
printf("m: %d\n", pthread_mutex_lock(&my_mutex));
pthread_mutex_unlock(&my_mutex);
return a;
}
void *m2(void *a)
{
printf("UNLOCKED!!: %d\n", pthread_mutex_lock(&my_mutex));
usleep(500 * 1000);
printf("m2: %d\n", pthread_mutex_lock(&my_mutex));
return a;
}
int main(int argc, const char * argv[])
{
pthread_t t,t2;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&my_mutex, &attr);
pthread_create(&t, NULL, m, NULL);
pthread_create(&t2, NULL, m2, NULL);
pthread_join(t, NULL);
pthread_join(t2, NULL);
return 0;
}
Gives
m: 0 11
m: 11
UNLOCKED!!: 0
m2: 11
Which means thread 2 has no chance to get the mutex while its locked.