c - 生产者消费者同步使用两个线程提供不正常的串行输出

标签 c multithreading producer-consumer

我正在使用两个线程解决生产者/消费者问题。我想我做错了什么,因为它似乎每次都提供相同的串行输出。有什么问题?

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <stdbool.h>

sem_t empty, full, mutex;

int bound[5];
int a,b;

void *producer(void *arg) {
    for (int i = 0; i < 15; i++) {
        sem_wait(&empty);
        sem_wait(&mutex);

        printf("%d is produced\n", i);
        sleep(1);

        bound[(++a) % 5] = i;

        sem_post(&mutex);
        sem_post(&full);
    }
}

void *consumer(void *arg) {
    int consumed;

    for (int i = 0; i < 15; i++) {
        sem_wait(&full);
        sem_wait(&mutex);

        consumed = bound[(++b) % 5];

        printf("%d is consumed\n",consumed);
        sleep(1);

        sem_post(&mutex);
        sem_post(&empty);
    }
}

void main() {
    pthread_t prod, con;

    sem_init(&mutex, 0, 1); 
    sem_init(&full, 0, 0);  
    sem_init(&empty, 0, 5);

    pthread_create(&prod,NULL,producer,NULL);
    pthread_create(&con,NULL,consumer,NULL);

    pthread_join(prod,NULL);
    pthread_join(con,NULL);
}

输出就像生产者先消费5次,然后消费者全部消费,然后生产者再次生产,重复:

0 is produced
1 is produced
2 is produced
3 is produced
4 is produced
0 is consumed
1 is consumed
2 is consumed
3 is consumed
4 is consumed
5 is produced

等等。

最佳答案

一些线程正在等待信号量的事实并不意味着一旦信号量的值变为非零它就一定会解除阻塞,即使它是当时唯一等待的线程。可能发生的事情之一是其他一些尚未等待的线程突袭并首先获取它。

例如,在您的代码中,生产者和消费者都向 mutex 信号量发送消息,然后循环并再次尝试获取它。除非被 other 信号量阻塞,否则一个线程完全有可能释放 mutex 然后重新获取它,而另一个线程不会在其间获取它。事实上,您的消费者和生产者似乎都以五个项目为一组进行操作——对应于 emptyfull 信号量的计数——表明这是在事实上正在发生的事情。

如果将 sleep 调用移到线程函数的关键区域之外,我希望您能获得完美的交替。你应该这样做,否则每个线程只有一个小窗口,它可以在其中接管另一个线程。

此外,虽然您可能会发现完美交替并不那么令人惊讶,但当您实现了一个长于一个项目的生产队列时,它也有些奇怪。我的意思是,如果队列中只有一项,为什么还要排长队呢?

为了看到所用队列容量的更多变化,您应该改变生产者和消费者的时间。您可能希望使用比 sleep() 提供的更高分辨率的计时器来实现它,否则您的运行将花费不必要的时间。

关于c - 生产者消费者同步使用两个线程提供不正常的串行输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51861200/

相关文章:

c++ - 使用 gdb 将数组内容打印到文件

c - C 预处理器中的 SIGN 宏

java - LMAX Disruptor - 什么决定了批量大小?

为消费者-生产者使用 ExecutorService 和 PipedReader/PipedWriter(或 PipedInputStream/PipedOutputStream)的 Java 示例

c - 如何将二进制字符串转换为多项式形式

c - 为什么 mtrace 实用程序不支持 mmap() 分配?

python - 无法理解为什么正常停止线程会在Windows下的(wx)Python中挂起该线程的其余执行代码

php - laravel 队列 - 同步驱动程序如何工作?它是在单独的进程/线程中执行还是在主执行线程中执行?

c# - 有没有办法无限期地暂停线程?

c# - 在 ConcurrentQueue 中尝试出队