I have two threads, a producer and a consumer. The producer thread recives data from another program through a named pipe at different rates, and forwards it to a consumer thread through a queue. The scheduler policy is RR and the producer thread has higher priority than the consumer thread. I want the producer to signal that there is new data on the queue, and have the consumer wait until the producer blocks, which will happen when there is no data to read from the named pipe.
The main thread sets the priorities:
policy = SCHED_FIFO;
pthread_attr_init(&tattr);
pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setschedpolicy(&tattr, policy);
param.sched_priority = sched_get_priority_max(policy);
pthread_attr_setschedparam(&tattr, ¶m);
pthread_create(&tid[0], &tattr, producer, fifo);
param.sched_priority = sched_get_priority_min(policy);
pthread_attr_setschedparam(&tattr, ¶m);
pthread_create(&tid[1], &tattr, consumer, fifo);
The producer does this:
fd = open(pipe, O_RDONLY);
while((read(fd, buf, 1024))!=0){
val = atoi(buf);
if(val > SOMETHING){
do_something();
} else {
pthread_mutex_lock (fifo->mut);
while (fifo->full) {
pthread_cond_wait (fifo->notFull, fifo->mut);
}
queueAdd (fifo, val);
pthread_mutex_unlock (fifo->mut);
pthread_cond_signal (fifo->notEmpty);
}
}
The consumer:
while(TRUE){
pthread_mutex_lock (fifo->mut);
while (fifo->empty) {
pthread_cond_wait (fifo->notEmpty, fifo->mut);
}
queueDel (fifo, &d);
do_something_else(d);
pthread_mutex_unlock (fifo->mut);
pthread_cond_signal (fifo->notFull);
}
After the signaling, the lower priority thread takes over. What am I doing wrong?
Thanks in advance!
EDIT: Changed the names of the threads. I had changed the names when posting it here, because my code is in spanish and the function names are something other than producer consumer, and made a mistake. But unluckily it's not that simple.
What I mean by 'takes over' is that the consumer continues execution. What I want is for it to start if and only if the producer thread blocks or exits.
It would be helpful if you were a little clearer about what you meant by 'the lower priority thread takes over' this would be easier to determine. But I don't think (with the code as it is) this has anything to do with scheduling policy.
From the POSIX spec (OK, from The Single UNIX Specification, Version 2, but same difference):
Now, because of your mutex ordering (see comment in final paragraph), the other thread does not hold the mutex when
pthread_cond_signalis performed. So, on a single CPU machine, we know it's going to get scheduled in regardless of scheduling policy, so the signalled thread will instantly grab the mutex, before the signalling thread manages to relock it. IE as only one thread is contending for the mutex at the time, the scheduling policy is irrelevant, and it will always get it.Is this what you are referring to?
Also, if
do_something_else(d);is in the slightest time-consuming, you don't want to do that with the mutex held, or it will stop the producer running.It's possible that there is another thing at play here. Another problem might be that your
pthread_cond_signalis not working because of a race condition. You don't have to callpthread_cond_signalwith the mutex held, but it is a good idea IMHO. In this instance, for instance, in the consumer you unlock the mutex after removing something from the queue, then do the signal. Between dropping the mutex and making the signal the FIFO may have changed state, and referring tofifo->notFullis technically unsafe. I suggest swapping thepthread_mutex_unlockand thepthread_cond_signalaround; this may also improve scheduling.EDIT
Now redundant as this was the OP's error, since fixed
Is this actually really simple? In your original message you say:However in your code:
Which looks to me like it's the consumer which is given maximum priority, and the producer which is given the minimum.