Pthread multi
[mirrors/Programs.git] / c / pthread_multi.c
1 /*
2 * CFLAGS=-lpthread make pthread_multi
3 */
4
5 #include <pthread.h>
6 #include <time.h>
7 #include <stdio.h>
8 #include <stdbool.h>
9
10 #define pthread_mutex_swap(a, b) ({ pthread_mutex_t *s; s = (a); a = (b); b = s; })
11
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)
15
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)
19
20 /*
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) {
24 int ret;
25
26 while(1) {
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!
30
31 //Try to lock the second mutex
32 ret = pthread_mutex_trylock(b);
33 if(!ret) return ret; //Locked BOTH Hooray!
34
35 //Unlock first if second failed to prevent deadlocks
36 pthread_mutex_unlock(a);
37
38 //Swap mutexes, so we will try to block on the second mutex next time:
39 pthread_mutex_swap(a, b);
40 //printf("Retry!\n");
41 }
42 }
43 */
44
45 int pthread_mutex_timedlock_multi_generic(pthread_mutex_t **lck, int cnt, bool block, const struct timespec *restrict abs_timeout) {
46 int ret, locked;
47
48 while(1) {
49 //Try to lock all mutexes
50 for(int i = 0; i<cnt; i++) {
51 //Block only on the first one
52 if(block && i==0) {
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
55 continue;
56 }
57 //Then try if we can lock the rest
58 ret = pthread_mutex_trylock(lck[i]);
59 if(ret) {
60 //Cannot lock this one
61 locked = i;
62 printf("Cannot lock #%d!\n", i);
63 break;
64 }
65 locked = i;
66 }
67
68 //Check if we managed to lock all locks
69 if(locked == cnt) return 0;
70
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]);
75 }
76 if(!block) return ret; //We do not want to block, just trying
77
78 //Try to block on locked mutex in next round
79 pthread_mutex_swap(lck[0],lck[locked]);
80 }
81 }
82
83 int main() {
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};
90
91 //Set timeout
92 struct timespec tm;
93 clock_gettime(CLOCK_REALTIME, &tm);
94 tm.tv_sec += 5;
95
96 //Lock one of the locks for testing
97 pthread_mutex_lock(lck[2]);
98
99 if(!pthread_mutex_timedlock_multi(lck, 4, &tm)) {
100 //if(!pthread_mutex_timedlock_two(&la, lck[2], &tm)) {
101 printf("LOCKED!\n");
102 } else {
103 printf("FAILED!\n");
104 }
105
106 }
This page took 0.31035 seconds and 4 git commands to generate.