【问题标题】:What do you do if you enqueue faster than dequeue?如果入队比出队快怎么办?
【发布时间】:2020-04-29 20:52:54
【问题描述】:

我正在使用 C 语言中的 pthreads。我有线程 1 从一个硬件接收数据,并将该数据放入队列中。当数据在队列中并处理该数据时,我有线程 2 会收到通知。我的实际代码的伪代码如下。

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

void* inputThread(void *ptr){
    while(){
        getData(var1); //Notified by external hardware interrupt when data is available. var1 will hold new data
        enqueue(q1, var1);
        pthread_mutex_lock(&lock1);
            pthread_cond_signal(&condition1);
        pthread_mutex_unlock(&lock1);
    }
}

void* processDataThread(void *ptr){
    short data_to_process[];
    while(){
        pthread_mutex_lock(&lock1);
            while (emptyqueue(q1)) { 
                    pthread_cond_wait(&condition1,&lock1); //wait for inputthread to fill queue
                }
            data_to_process=dequeue(q1);
        pthread_mutex_unlock(&lock1);

        process_data(data_to_process); //causes thread to slow down
    }
}

int main(void){
    pthread_t input_thread_id;
    pthread_t thr[10];
    struct queue q1;
    struct queue q2;

    //
    //
    //some code to initiate queues, locks/mutex, conditions, etc.
    //
    //

    for (j) {
        pthread_create(&thr[j], NULL, processDataThread,(void*) &ptr);  
    }
    sleep(3); //sleep to let processthreads start up
    pthread_create(&input_thread_id, NULL, inputThread,(void*) &ptr);
}

我确信入队和出队工作正常。我写了一个文件并验证了我在 inputThread 中收到的任何内容都已出列。将process_data() 函数放入代码时出现问题。该函数会减慢 processDataThread 的速度,导致 inputThread 在 processDataThread 可以出队之前填满队列。这会导致丢失数据,因为 inputThread 的工作速度比 processDataThread 快。如果我注释掉 `process_data()' 函数,队列不会溢出。即使增加了 processDataThreads 的数量(我尝试了 3、5 和 10 个),队列的入队速度仍然比出队快。

runtime getData() to dequeue() 为 0.01s,程序连续循环运行,没有队列填充 getData()process_data() 的运行时间是 0.05 秒,几秒钟后队列就会填满。

我做错了什么?我认为增加 processDataThread 的数量会比 dequeue 更快地解决入队问题,但事实并非如此。

【问题讨论】:

  • 有多少个内核可用? process_data cpu 绑定了吗?
  • 也许这只是一个错字,但 enqueue 函数不应该在关键部分内吗?而且增加队列大小根本没有帮助?
  • 这毫无意义:pthread_mutex_lock(&amp;lock1); pthread_cond_signal(&amp;condition1); pthread_mutex_unlock(&amp;lock1); ...好吧,没有我想象的那么糟糕。只是效率低下。对pthread_cond_signal 的调用应该在enqueue 内部,并且在释放锁之前调用
  • 请提供一个最小的、可运行的问题演示。见minimal reproducible example
  • @AnaKhorguani 我的印象是,由于只有一个线程一直在排队,它不必在关键部分内。 Enqueue 只涉及 tail,而 dequeue 涉及 head。出队在关键部分内,因为超过 1 个线程访问该函数。

标签: c queue pthreads mutex


【解决方案1】:

该函数会减慢processDataThread,导致inputThread在processDataThread出队之前就填满了队列。

这很正常。线程完成的工作通常比为这些线程生成输入要慢(这可能就像从文件中读取行一样简单)。请记住,我们使用线程来并行化慢速进程。

这会导致数据丢失

如果丢失数据,您的队列有问题!

我确信入队和出队工作正常。

不,丢失数据的队列没有“工作”。


您没有按要求显示您尝试调试的代码,因此我们只能猜测问题所在。听起来您有一个固定大小的队列,如果队列已满,enqueue 只是放弃要添加到队列的项目。这是一个错误。

如果这是问题所在,要么在队列满时增加队列,要么阻塞直到有空间将您想要加入的内容加入队列。 This working queue implementation 是后者。

【讨论】:

  • 感谢您的帮助!队列实际上没有任何问题。我必须在这个项目中有一个固定的队列大小。如果我在队列已满时增加队列,最终队列会太大,因为它不能解决数据入队速度比出队速度快的问题。如果我阻塞,那么我会错过无法入队的数据。我无法仅仅因为我的队列已满而停止外部硬件向我发送数据。
  • 问题已通过更改 processData() 函数以更快地运行来解决。问题也可以通过减慢来自外部硬件的数据来解决,但这对我的项目来说不是一个好的解决方案。我有一个单核系统,这就是为什么增加处理线程数量没有帮助的原因。
  • Re“队列实际上没有问题。”,你说它丢失了数据,然后你问如何避免这种情况。如果这不是问题,你为什么要问如何解决它?您还展示了调用者必须处理内部事务,例如信号
  • Re "如果我阻塞,那么我会错过无法入队的数据",除非您对实时数据进行采样,否则这没有任何意义,在这种情况下,您不能使用固定大小的队列而不冒数据丢失的风险,除非您可以保证消费者比生产者更快地处理数据。 (您可以使用文件或数据库作为提供 MT 队列的队列)。但您的问题与此无关。
  • 如果您使用的是动态大小的队列,而消费者消费数据的速度不够快,那么最终您的队列将太大。我最初的问题是询问我的消费者代码是否错误。能够入队和出队的队列是正确的,但入队的发生速度比出队快。这就是我要求解决的问题。它最终成为单核的硬件问题,我认为我有多个核心。这就是混乱的来源。发现这一点后,我修复了消费者的运行速度比传入的数据快,并且我使用的是一个线程。
猜你喜欢
  • 2013-06-05
  • 2020-04-19
  • 2018-06-20
  • 2017-02-21
  • 2015-11-23
  • 2015-10-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
相关资源
最近更新 更多