我有两个生产者 - 消费者模式的线程。代码有效,但是消费者线程会变得饥饿,然后生产者线程会变得饥饿。
工作时,程序输出:
Send Data...semValue = 1
Recv Data...semValue = 0
Send Data...semValue = 1
Recv Data...semValue = 0
Send Data...semValue = 1
Recv Data...semValue = 0
然后一些事情发生变化,线程变得饥饿,程序输出:
Send Data...semValue = 1
Send Data...semValue = 2
Send Data...semValue = 3
...
Send Data...semValue = 256
Send Data...semValue = 257
Send Data...semValue = 258
Recv Data...semValue = 257
Recv Data...semValue = 256
Recv Data...semValue = 255
...
Recv Data...semValue = 0
Send Data...semValue = 1
Recv Data...semValue = 0
Send Data...semValue = 1
Recv Data...semValue = 0
我知道线程是由操作系统安排的,可以以不同的速率和随机顺序运行。我的问题:当我执行YieldThread(调用pthread_yield)时,Talker不应该给Listener一个运行机会吗?为什么我会得到这个奇怪的日程安排?
以下代码片段。 Thread类和Semaphore类是抽象类。我继续排除了线程之间传递数据的队列,因此我可以消除该变量。
const int LOOP_FOREVER = 1;
class Listener : public Thread
{
public:
Listener(Semaphore* dataReadySemaphorePtr)
: Thread("Listener"),
dataReadySemaphorePtr(dataReadySemaphorePtr)
{
//Intentionally left blank.
}
private:
void ThreadTask(void)
{
while(LOOP_FOREVER)
{
this->dataReadySemaphorePtr->Wait();
printf("Recv Data...");
YieldThread();
}
}
Semaphore* dataReadySemaphorePtr;
};
class Talker : public Thread
{
public:
Talker(Semaphore* dataReadySemaphorePtr)
: Thread("Talker"),
dataReadySemaphorePtr(dataReadySemaphorePtr)
{
//Intentionally left blank
}
private:
void ThreadTask(void)
{
while(LOOP_FOREVER)
{
printf("Send Data...");
this->dataReadySemaphorePtr->Post();
YieldThread();
}
}
Semaphore* dataReadySemaphorePtr;
};
int main()
{
Semaphore dataReadySemaphore(0);
Listener listener(&dataReadySemaphore);
Talker talker(&dataReadySemaphore);
listener.StartThread();
talker.StartThread();
while (LOOP_FOREVER); //Wait here so threads can run
}
答案 0 :(得分:2)
没有。除非你使用锁来阻止它,即使一个线程产生它的量子,也不要求另一个线程接收下一个量子。
在多线程环境中,您可以永远不会对如何安排处理器时间做出假设;如果您需要强制执行正确的行为,请使用锁定。
答案 1 :(得分:1)
信不信由你,它以这种方式运行,因为它更有效率。每次处理器在线程之间切换时,它都会执行浪费一定时间的上下文切换。我的建议是放手,除非你有另一个要求,如最大延迟或队列大小,在这种情况下,你需要另一个信号量“准备好更多数据”,除了你的“数据准备好听”之外。