简体   繁体   English

pthread中的条件变量和实时优先级

[英]Condition variables and real time priorities in pthreads

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. 调度程序策略为RR,生产者线程的优先级高于消费者线程。 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, &param);
pthread_create(&tid[0], &tattr, producer, fifo);

param.sched_priority = sched_get_priority_min(policy);
pthread_attr_setschedparam(&tattr, &param);
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): 从POSIX规范(确定,从Single UNIX规范,版本2 ,但相同):

If more than one thread is blocked on a condition variable, the scheduling policy determines the order in which threads are unblocked. 如果在一个条件变量上阻塞了多个线程,则调度策略将确定解除阻塞线程的顺序。 When each thread unblocked as a result of a pthread_cond_signal() or pthread_cond_broadcast() returns from its call to pthread_cond_wait() or pthread_cond_timedwait() , the thread owns the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait() . 当每个由于pthread_cond_signal()pthread_cond_broadcast()的结果而解除阻塞的线程从其对pthread_cond_wait()pthread_cond_timedwait()调用返回时,该线程将拥有互斥量,该互斥量将其称为pthread_cond_wait()pthread_cond_timedwait() The thread(s) that are unblocked contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock() . 根据调度策略(如果适用),未阻塞的线程争用互斥锁,就好像每个线程都调用了pthread_mutex_lock()

Now, because of your mutex ordering (see comment in final paragraph), the other thread does not hold the mutex when pthread_cond_signal is performed. 现在,由于您的互斥锁排序(请参见最后一段中的注释),执行pthread_cond_signal时,另一个线程将不保留该互斥锁。 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. 因此,在单台CPU机器上,我们知道无论调度策略如何,都将对其进行调度,因此在信号线程设法重新锁定互斥对象之前,被信号线程将立即获取互斥对象。 IE as only one thread is contending for the mutex at the time, the scheduling policy is irrelevant, and it will always get it. IE由于当时只有一个线程在争用互斥锁,因此调度策略是无关紧要的,并且总是会得到它。

Is this what you are referring to? 这是您所指的吗?

Also, if do_something_else(d); 另外,如果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_signal is not working because of a race condition. 另一个问题可能是您的pthread_cond_signal由于竞争条件而无法正常工作。 You don't have to call pthread_cond_signal with the mutex held, but it is a good idea IMHO. 不必调用pthread_cond_signal在持有互斥体,但它是一个好主意,恕我直言。 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 to fifo->notFull is technically unsafe. 在丢弃互斥锁并发出信号之前,FIFO可能已更改状态,而引用fifo->notFull在技​​术上是不安全的。 I suggest swapping the pthread_mutex_unlock and the pthread_cond_signal around; 我建议交换一下pthread_mutex_unlockpthread_cond_signal this may also improve scheduling. 这也可以改善调度。

EDIT 编辑

Now redundant as this was the OP's error, since fixed 现在已修复,因为这是OP的错误,因为已修复

Is this actually really simple? 这真的很简单吗? In your original message you say: 在原始消息中,您说:

The scheduler policy is RR and the producer thread has higher priority than the consumer thread. 调度程序策略为RR,生产者线程的优先级高于消费者线程。

However in your code: 但是在您的代码中:

 param.sched_priority = sched_get_priority_max(policy); pthread_attr_setschedparam(&tattr, &param); pthread_create(&tid[0], &tattr, consumerr, fifo); param.sched_priority = sched_get_priority_min(policy); pthread_attr_setschedparam(&tattr, &param); pthread_create(&tid[1], &tattr, producer, fifo); 

Which looks to me like it's the consumer which is given maximum priority, and the producer which is given the minimum. 在我看来,这是给消费者最大的优先级,而给生产者最小的优先级。

Try to compile your project with optimizations DISABLED , because if you have them enabled right now and the variables fifo->empty and fifo->full are NOT declared volatile, then there is a big possibility that compiler optimizes some parts of your code in a way that you wouldn't like - the value is tested only once, and if it is true your code falls into an endless loop (the one with pthread_cond_wait() ) that it will not leave no matter what, because compiler cannot see how pthread_cond_wait() could alter it. 尝试使用DISABLED优化禁用编译您的项目,因为如果立即启用它们,并且变量fifo-> empty和fifo-> full 没有声明为volatile,那么编译器很有可能会优化代码中的某些部分。您不希望的方式-该值仅测试一次,如果为true,则您的代码会陷入无限循环(带有pthread_cond_wait()循环),无论如何都不会pthread_cond_wait() ,因为编译器无法看到pthread_cond_wait()样子pthread_cond_wait()可以更改它。

If that's not it, then the behavior you describe is still not clear to me... Your example should work in the following way: 如果不是那样,那么您描述的行为对我来说仍然不清楚...您的示例应以以下方式工作:

  • producer puts something in the queue until it's full, then blocks, 生产者将某些东西放入队列,直到填满,然后阻止,
  • consumer takes the item from the queue, and signals the producer that there is one free slot, 消费者从队列中取出商品,并告知生产者有一个空闲位置,
  • producer wakes up (assuming it's not blocked on read() ) and puts one item into the queue (that's the whole free space), then blocks, 生产者醒来(假设它没有在read()上被阻塞),然后将一项放入队列(即整个可用空间),然后阻塞,
  • ... ...

How is the behavior you see different from what you expect? 您看到的行为与预期的有何不同? How can consumer "take over" when there's no data in the queue? 当队列中没有数据时,消费者如何“接管”? It should stop "taking over" after the first (which is also the last) element taken from the queue and wait for producer to add anything. 它应该在从队列中获取第一个(也是最后一个)元素之后停止“接管”,并等待生产者添加任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM