I'm using the following conditional thread to lock 10 threads using FIFO scheduling, I need to unlock the threads in the order with which they have arrived to pthread_cond_wait(&cvv, &lock); I need to know if that is possible or there is no guarantee to have this scenario.
struct sched_param param = {.sched_priority = 10};
pthread_cond_t cvv = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
void *thread(void *v) {
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
int index = *((int *)v);
printf("Locking [%d] and waiting\n", index);
pthread_mutex_lock(&lock);
pthread_cond_wait(&cvv, &lock);
printf("Unlockd [%d] => %d\n", index, clock());
pthread_mutex_unlock(&lock);
return NULL;
}
int main(int argc, char** argv) {
for (int i = 0; i < 10; i++) {
t = (pthread_t *) malloc(sizeof (pthread_t));
int *x = malloc(sizeof (int));
*x = i;
pthread_create(t, NULL, thread, x);
}
for (int i = 0; i < 10; i++) {
pthread_cond_signal(&cvv);
}
}
The out put is not in ascendant ordered
Locking [0] and waiting
Locking [1] and waiting
Locking [2] and waiting
Locking [3] and waiting
Locking [4] and waiting
Locking [5] and waiting
Locking [6] and waiting
Locking [7] and waiting
Locking [8] and waiting
Locking [9] and waiting
Unlocked [0] => 7043
Unlocked [8] => 7084
Unlocked [6] => 7100
Unlocked [2] => 7130
Unlocked [5] => 7294
Unlocked [7] => 7362
Unlocked [3] => 7407
Unlocked [1] => 7463
Unlocked [9] => 7482
Unlocked [4] => 7559
pthread_setschedparam
is probably not available to you, as it requires privilege. You do not check the return values of these calls, but you will likely find that they are failing with EPERM
. They do so for me.
I need to unlock the threads in the order with which they have arrived to pthread_cond_wait(&cvv, &lock); I need to know if that is possible or there is no guarantee to have this scenario.
Yes, you can do this, but you will need to roll your own. Here's one scheme that can accomplish it:
establish three global counters, say in
, out
, and next
, access to which are protected by the mutex. Initialize all of them to 0.
Each thread passes through the lock like so:
in
and records the new value. This is its "ticket".next
and next
is less than or equal to out
, and waits on the CV only if one or both of these conditions is not met.next
.next
.to unlock the next thread,
out
next
is still 0 then increment it, toopthread_cond_broadcast
(not pthread_cond_signal
)Of course, all accesses to in
, out
, and next
must be performed under protection of the mutex, which should be the same one used with the CV.
Note that that scheme permits threads to grant unlocks prospectively, when no threads are presently locked. That will actually solve one of the problems with your current implementation, but if you prefer, you can rework it using only in
and next
, making the thread performing the unlocking wait until in
exceeds next
. This can be achieved with use of the same CV. Details are left as an exercise.