生产者使用者同步使用两个线程提供异常的串行输出

时间:2018-08-15 14:57:22

标签: c multithreading producer-consumer

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

public function up()
{
    Schema::table('posts', function (Blueprint $table) {
        $table->integer('user_id')->unsigned()->change();
    });
    Schema::table('posts', function (Blueprint $table) {
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}

输出就像生产者首先消耗5倍,然后消费者将它们全部消耗掉,然后生产者再次生产并重复:

#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);
}

以此类推。

2 个答案:

答案 0 :(得分:2)

某个线程正在等待信号量的事实并不意味着它必须在信号量的值变为非零时立即解除阻塞,即使它是当时唯一的等待状态。在可能发生的事情中,还有一些尚未等待的线程突然涌入并首先获取它。

例如,在您的代码中,生产者和消费者都将发布到ID信号量,然后循环并尝试再次获取它。除非被 other 信号量阻止,否则一个线程完全有可能释放mutex,然后重新获取它,而另一线程之间则没有。您的消费者和生产者似乎分别以五个项目为一组进行操作,这与mutexempty信号量所得到的计数相对应,这表明这实际上是正在发生的事情。 / p>

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

此外,尽管您可能会发现完美的轮换并不令人惊讶,但当您实施的生产队列超过一个项目时,它也有些奇怪。我的意思是,如果其中不超过一个项目,为什么还要麻烦一个队列?

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

答案 1 :(得分:0)

仅仅因为一个线程发布了一个信号量,另一个线程正在等待,所以不能保证另一个线程可以立即运行。如果第一个线程非常快,则可能在另一个线程开始运行之前重新获得信号量。这可能是您看到5个产生的和5个消耗的交替序列的原因。

尝试使buf更大(例如1000),并在生产者和消费者中进行1500次循环(也更改sem_init)。然后,您可能会看到另一种模式。

顺便说一句:删除两个睡眠呼叫。它们在您按住mutex时完成,因此其他线程无论如何都无法运行。