如何在两个线程中使用队列——一个用于消费者,一个用于生产者
Posted
技术标签:
【中文标题】如何在两个线程中使用队列——一个用于消费者,一个用于生产者【英文标题】:How to use queue with two threads-- one for consumer and one for producer 【发布时间】:2009-03-13 05:27:50 【问题描述】:我正在使用一个应用程序,其中较低级别的应用程序在接收数据时总是调用回调 RecData(char *buf)。
在回调中,我创建了两个线程,并将消费者和生产者函数分别传递给这些创建的线程。
我的代码:
void RecData (char * buf)
CreateThread(NULL,0,producer_queue,(void *)buf,0,NULL);
CreateThread(NULL,0,consumer_queue,NULL,0,NULL);
当我一次收到一个数据时,上述方法有效。如果我几乎同时收到 5 个数据,那么 producer_queue 应该首先将所有数据放入队列中,然后 consumer_queue 应该开始检索数据,但是在这里一旦 producer_queue 将第一个数据放入队列中,consumer_queue 就会检索它。
【问题讨论】:
每次接收数据时产生 2 个线程有什么原因吗? 不,我唯一的动机是将数据排入队列,然后从队列中读取数据,但如果我只是在 RecData (char * buf) 函数中为生产者放置一个线程,那么我将如何以及何时开始从队列中读取数据。请帮忙 另一种方法可能是生成单个阅读器线程。在 RecCall 中,您只需锁定队列,然后将数据排入队列。您的 Reader 线程将循环从队列中读取数据。只是一个想法。 你能告诉我我应该如何编码这个..请输入几行代码来完成它 【参考方案1】:我相信您想要做的是控制对队列的访问。你会想看看使用互斥锁来控制从队列中读取。
当您收到数据时,您将锁定互斥锁,然后将数据排入队列。完成对数据的排队后,释放锁。
从队列中读取时,您会看到互斥体是否被锁定。如果您正在将数据写入队列,您将无法开始读取,直到您的生产者线程完成写入所有数据并释放锁。如果您确实锁定了互斥锁,那么您在读取数据时会阻止写入器线程写入。
这种方法可能会引入潜在的死锁。如果您的写入线程在释放锁之前死亡,那么您的读取线程将无法继续(然后您的线程死亡可能会再次触发错误状态)。
我希望这是有道理的。
【讨论】:
嗨艾伦,我在问题中提到的上述代码实际发生的情况是生产者线程和消费者线程总是一个接一个地创建。 说如果 RecData (char * buf) 回调几乎同时接收到 5 个数据,那么为了在队列中写入第一个数据,它会为生产者创建一个线程,将其写入队列然后接下来它再创建一个线程(消费者)来读取数据,下一个数据也会发生同样的情况。 我希望它的行为类似于当它收到 5 个数据时,生产者应该将所有 5 个数据写入队列,然后消费者线程应该开始从队列中读取这 5 个数据。是否可以?谢谢 你是说 RedData 被调用了 5 次? yes..exactly..每次在队列中写入数据然后调用下一个consumer_queue来读取数据..【参考方案2】:使用条件变量的概念。您拥有的问题是多线程编程世界中最常见的问题。仅使用互斥锁无济于事。永远记住,互斥锁是用于锁定的,而条件变量是用于等待的。后者总是更安全,并且几乎可以肯定线程何时应该开始从共享队列中消费。
查看以下链接,了解如何在 Windows 上自行创建条件变量: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
如果您使用的是 windows vista,下面的 msdn 示例可能会对您有所帮助: http://msdn.microsoft.com/en-us/library/ms686903(VS.85).aspx
在所有情况下都使用 Schmidt 网站中显示的逻辑,因为它看起来更便携(哦,是的,至少在不同版本的 Windows 上可移植)。 Schmidt 的实现为您提供了标准 POSIX api 的感觉,这是大多数现代 UNIX/LINUX 系统上广泛使用的标准。
【讨论】:
你的 msdn 链接有点乱。以上是关于如何在两个线程中使用队列——一个用于消费者,一个用于生产者的主要内容,如果未能解决你的问题,请参考以下文章
什么是阻塞队列?阻塞队列的实现原理是什么?如何使用 阻塞队列来实现生产者-消费者模型?
什么是阻塞队列?阻塞队列的实现原理是什么?如何使用 阻塞队列来实现生产者-消费者模型?