pthread调度问题

时间:2010-08-30 21:51:29

标签: c++ pthreads scheduling yield

我有两个生产者 - 消费者模式的线程。代码有效,但是消费者线程会变得饥饿,然后生产者线程会变得饥饿。

工作时,程序输出:

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
}

2 个答案:

答案 0 :(得分:2)

没有。除非你使用锁来阻止它,即使一个线程产生它的量子,也不要求另一个线程接收下一个量子。

在多线程环境中,您可以永远不会对如何安排处理器时间做出假设;如果您需要强制执行正确的行为,请使用锁定。

答案 1 :(得分:1)

信不信由你,它以这种方式运行,因为它更有效率。每次处理器在线程之间切换时,它都会执行浪费一定时间的上下文切换。我的建议是放手,除非你有另一个要求,如最大延迟或队列大小,在这种情况下,你需要另一个信号量“准备好更多数据”,除了你的“数据准备好听”之外。