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

时间:2014-11-25 18:33:32

标签: c pthreads thread-priority

我有两个线程,一个生产者和一个消费者。生产者线程通过命名管道以不同的速率从另一个程序中获取数据,并通过队列将其转发给使用者线程。调度程序策略是RR,生产者线程的优先级高于使用者线程。我希望生产者发信号通知队列中有新数据,并让消费者等到生产者阻塞,这将在没有数据从命名管道中读取时发生。

主线程设置优先级:

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);

制作人这样做:

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);
    }
}

消费者:

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);
}

信令发出后,优先级较低的线程接管。我做错了什么?

提前致谢!

编辑:更改了线程的名称。我在这里发布时更改了名称,因为我的代码是西班牙语,函数名称不是生产者消费者,而且是错误的。但不幸的是,事情并非那么简单。

我的意思是'接管'是消费者继续执行。我想要的是,当且仅当生产者线程阻塞或退出时才开始。

2 个答案:

答案 0 :(得分:0)

如果您对'低优先级线程接管'的含义更清楚一点会更有帮助,这将更容易确定。但我不认为(使用代码)这与调度策略有关。

从POSIX规范(好的,来自The Single UNIX Specification, Version 2,但相同的区别):

  

如果在条件变量上阻塞了多个线程,则调度策略将确定线程被解除阻塞的顺序。当pthread_cond_signal()pthread_cond_broadcast()因调用pthread_cond_wait()pthread_cond_timedwait()而返回时,每个线程都会解锁,该线程拥有与其pthread_cond_wait()调用的互斥锁}或pthread_cond_timedwait()。根据调度策略(如果适用),未阻塞的线程将争用互斥锁,并且好像每个线程都调用了pthread_mutex_lock()

现在,由于您的互斥量排序(请参阅最后一段中的注释),另一个线程在执行pthread_cond_signal时不会保留互斥锁。因此,在单个CPU机器上,我们知道它将在不管调度策略的情况下进行调度,因此在信令线程设法重新锁定它之前,发出信号的线程将立即获取互斥锁。 IE作为当时只有一个线程争用互斥锁,调度策略是无关紧要的,它总会得到它。

这是你指的是什么?

另外,如果do_something_else(d);最耗时,您不希望使用互斥锁执行此操作,否则会阻止生产者运行。

这可能还有其他的事情在这里发挥作用。另一个问题可能是您的pthread_cond_signal由于竞争条件而无法正常工作。您没有 在保持互斥锁的情况下呼叫pthread_cond_signal,但恕我直言。在这种情况下,例如,在消费者中,您在从队列中删除某些内容后解锁互斥锁,然后执行信号。在丢弃互斥锁并使信号FIFO可能已经改变状态之间,并且引用fifo->notFull在技术上是不安全的。我建议交换pthread_mutex_unlockpthread_cond_signal左右;这也可能会改善日程安排。

修改

现在多余,因为这是OP的错误,因为修复了

这真的很简单吗?在原始邮件中,您说:

  

调度程序策略是RR,生产者线程的优先级高于使用者线程。

但是在你的代码中:

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);

在我看来,它是消费者,它被赋予最大优先权,而生产者被给予最低限度。

答案 1 :(得分:0)

尝试使用优化 DISABLED 编译项目,因为如果你现在启用它们并且变量fifo-> empty和fifo-> full是 NOT 声明为volatile,那么编译器很有可能以你不喜欢的方式优化代码的某些部分 - 值只测试一次,如果是真的,你的代码就会陷入无限循环(一个pthread_cond_wait()),无论如何都不会离开,因为编译器无法看到pthread_cond_wait()如何改变它。

如果不是这样,那么您描述的行为对我来说仍然不明确......您的示例应该以下列方式运作:

  • 生产者将一些东西放入队列,直到它满了,然后阻塞,
  • 使用者从队列中获取该项,并向生产者发出信号,表明有一个空闲插槽
  • 生产者醒来(假设它未在read()上被阻止)并将一个项目放入队列(这是整个可用空间),然后是块,
  • ...

您看到的行为与您的期望有何不同?消费者如何接管"当队列中没有数据时?它应该停止"接管"在从队列中取出的第一个(也是最后一个)元素之后,等待生产者添加任何东西。

相关问题