我有两个线程,一个生产者和一个消费者。生产者线程通过命名管道以不同的速率从另一个程序中获取数据,并通过队列将其转发给使用者线程。调度程序策略是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, ¶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);
制作人这样做:
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);
}
信令发出后,优先级较低的线程接管。我做错了什么?
提前致谢!
编辑:更改了线程的名称。我在这里发布时更改了名称,因为我的代码是西班牙语,函数名称不是生产者消费者,而且是错误的。但不幸的是,事情并非那么简单。
我的意思是'接管'是消费者继续执行。我想要的是,当且仅当生产者线程阻塞或退出时才开始。
答案 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_unlock
和pthread_cond_signal
左右;这也可能会改善日程安排。
现在多余,因为这是OP的错误,因为修复了
这真的很简单吗?在原始邮件中,您说:
调度程序策略是RR,生产者线程的优先级高于使用者线程。
但是在你的代码中:
param.sched_priority = sched_get_priority_max(policy);
pthread_attr_setschedparam(&tattr, ¶m);
pthread_create(&tid[0], &tattr, consumerr, fifo);
param.sched_priority = sched_get_priority_min(policy);
pthread_attr_setschedparam(&tattr, ¶m);
pthread_create(&tid[1], &tattr, producer, fifo);
在我看来,它是消费者,它被赋予最大优先权,而生产者被给予最低限度。
答案 1 :(得分:0)
尝试使用优化 DISABLED 编译项目,因为如果你现在启用它们并且变量fifo-> empty和fifo-> full是 NOT 声明为volatile,那么编译器很有可能以你不喜欢的方式优化代码的某些部分 - 值只测试一次,如果是真的,你的代码就会陷入无限循环(一个pthread_cond_wait()
),无论如何都不会离开,因为编译器无法看到pthread_cond_wait()
如何改变它。
如果不是这样,那么您描述的行为对我来说仍然不明确......您的示例应该以下列方式运作:
read()
上被阻止)并将一个项目放入队列(这是整个可用空间),然后是块,您看到的行为与您的期望有何不同?消费者如何接管"当队列中没有数据时?它应该停止"接管"在从队列中取出的第一个(也是最后一个)元素之后,等待生产者添加任何东西。