2 * CFLAGS=-lpthread make pthread_multi
10 #define pthread_mutex_swap(a, b) ({ pthread_mutex_t *s; s = (a); a = (b); b = s; })
12 #define pthread_mutex_lock_two(a,b) pthread_mutex_timedlock_multi_generic((pthread_mutex_t *[2]){(a), (b)}, 2, true, NULL)
13 #define pthread_mutex_timedlock_two(a,b,tm) pthread_mutex_timedlock_multi_generic((pthread_mutex_t *[2]){(a), (b)}, 2, true, (tm))
14 #define pthread_mutex_trylock_two(a,b) pthread_mutex_timedlock_multi_generic((pthread_mutex_t *[2]){(a), (b)}, 2, false, NULL)
16 #define pthread_mutex_lock_multi(lcks,cnt) pthread_mutex_timedlock_multi_generic((lcks),(cnt),true,NULL)
17 #define pthread_mutex_timedlock_multi(lcks,cnt,tm) pthread_mutex_timedlock_multi_generic((lcks),(cnt),true,(tm))
18 #define pthread_mutex_trylock_multi(lcks,cnt) pthread_mutex_timedlock_multi_generic((lcks),(cnt),false,NULL)
21 //This is first prototype for two mutexes only, it is useful in order to understand how this all works
22 //Currently it was replaced by macro with the same name
23 int pthread_mutex_timedlock_two(pthread_mutex_t *a, pthread_mutex_t *b, const struct timespec *restrict abs_timeout) {
27 //Wait for the first mutex
28 ret = (abs_timeout==NULL ? pthread_mutex_lock(a) : pthread_mutex_timedlock(a, abs_timeout));
29 if(ret) return ret; //Something is fishy about this mutex. Abort!
31 //Try to lock the second mutex
32 ret = pthread_mutex_trylock(b);
33 if(!ret) return ret; //Locked BOTH Hooray!
35 //Unlock first if second failed to prevent deadlocks
36 pthread_mutex_unlock(a);
38 //Swap mutexes, so we will try to block on the second mutex next time:
39 pthread_mutex_swap(a, b);
45 int pthread_mutex_timedlock_multi_generic(pthread_mutex_t
**lck
, int cnt
, bool block
, const struct timespec
*restrict abs_timeout
) {
49 //Try to lock all mutexes
50 for(int i
= 0; i
<cnt
; i
++) {
51 //Block only on the first one
53 ret
= (abs_timeout
==NULL
? pthread_mutex_lock(lck
[i
]) : pthread_mutex_timedlock(lck
[i
], abs_timeout
));
54 if(ret
) return ret
; //Something went wrong
57 //Then try if we can lock the rest
58 ret
= pthread_mutex_trylock(lck
[i
]);
60 //Cannot lock this one
62 printf("Cannot lock #%d!\n", i
);
68 //Check if we managed to lock all locks
69 if(locked
== cnt
) return 0;
71 //Unlock all mutexes that we managed to lock so far
72 for(int i
= 0;i
<locked
;i
++) {
73 printf("Unlocking #%d\n", i
);
74 pthread_mutex_unlock(lck
[i
]);
76 if(!block
) return ret
; //We do not want to block, just trying
78 //Try to block on locked mutex in next round
79 pthread_mutex_swap(lck
[0],lck
[locked
]);
84 //Prepare mutex array for tests
85 static pthread_mutex_t la
= PTHREAD_MUTEX_INITIALIZER
;
86 static pthread_mutex_t lb
= PTHREAD_MUTEX_INITIALIZER
;
87 static pthread_mutex_t lc
= PTHREAD_MUTEX_INITIALIZER
;
88 static pthread_mutex_t ld
= PTHREAD_MUTEX_INITIALIZER
;
89 static pthread_mutex_t
*lck
[4] = {&la
, &lb
, &lc
, &ld
};
93 clock_gettime(CLOCK_REALTIME
, &tm
);
96 //Lock one of the locks for testing
97 pthread_mutex_lock(lck
[2]);
99 if(!pthread_mutex_timedlock_multi(lck
, 4, &tm
)) {
100 //if(!pthread_mutex_timedlock_two(&la, lck[2], &tm)) {