【问题标题】:Producer-consumer using semaphore in C在 C 中使用信号量的生产者-消费者
【发布时间】:2018-10-05 23:54:06
【问题描述】:

有一个生产者-消费者问题是用信号量写的。在下面的代码中,在创建消费者时存在同步执行问题。对于它的解决方案,在消费者的 switch 块中添加了 sleep 语句。
请帮助我提供有效的同步解决方案。任何改进代码的建议都非常有帮助。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<semaphore.h> /* sem_t */
#include<stdlib.h>

#define BUF_SIZE 2

struct buffer {
        int data;
};

struct buffer buf[BUF_SIZE];

sem_t fill, empty;

int value, i;

void *producer(void *data);
void *consumer(void *data);

int main(void)
{
    int sel, prod_data, cons_data;
    int k;

    if (sem_init(&empty, 0, BUF_SIZE)) {
        printf("Error: semaphore not initialize\n");
        return -1;
    }
    if (sem_init(&fill, 0, 0)) {
        printf("Error: semaphore not initialize\n");
        return -1;
    }

    while (1) {
        printf(".........................................................\n");
        printf("Selection\n");
        printf("Producer : 1 | Consumer : 2 | Display : 3 | Exit : 0 || ");
        scanf("%d",&sel);
        printf(".........................................................\n");

        switch (sel) {
        case 1:
            sem_getvalue(&empty, &value);
//          printf("Prod_e: %d\n", value);
            sem_getvalue(&fill, &value);
//          printf("Prod_f: %d\n", value);
            printf("\nProducer\n");
            pthread_t prod_t;
            printf("Enter data:");
            scanf("%d", &prod_data);
            if (pthread_create(&prod_t, NULL, producer, (void *) &prod_data)) {
                printf("Error: thread not created\n");
                return -1;
            }
            break;
        case 2:
            printf("\nConsumer\n");
            sem_getvalue(&empty, &value);
//          printf("Cons_e: %d\n", value);
            sem_getvalue(&fill, &value);
//          printf("Cons_f: %d\n", value);
            pthread_t con_t;
            if (pthread_create(&con_t, NULL, consumer, (void *) &cons_data)) {
                printf("Error: thread not created\n");
                return -1;
            }
            if (i == 0) {
                printf("Buffer empty\n");
                break;
            }
//              sleep(1); // if commented then synchronization issue
            printf("Consume data: %d\n", cons_data);
            break;
        case 3:
                if (i == 0) {
                    printf("Buffer empty\n");
                    break;
                }
                for (k = 0; k < i; k++)
                    printf("buf[%d]: %d\n", k, buf[k].data);
                break;
        case 0:
            sem_destroy(&fill);
            sem_destroy(&empty);
            exit (0);
            break;
        }
    }
    sem_destroy(&fill);
    sem_destroy(&empty);
    return 0;
}

void *producer(void *arg)
{
    int data = *(int *) arg;

    if (sem_wait(&empty)) { /* wait */
        printf("Error: sem wait fail\n");
        pthread_exit(NULL);
    }

    buf[i].data = data;
    i++;

    if (sem_post(&fill)) { /* post */
        printf("Error: sem wait fail\n");
        pthread_exit(NULL);
    }

    pthread_exit(NULL);
}

void *consumer(void *arg)
{

    if (sem_wait(&fill)) { /* wait */
        printf("Error: sem wait fail\n");
        pthread_exit(NULL);
    }

    i--;
    *(int *) arg = buf[i].data;

    if (sem_post(&empty)) { /* post */
        printf("Error: sem wait fail\n");
        pthread_exit(NULL);
    }
    pthread_exit(NULL);
}


没有 sleep 语句的输出:

Selection
Producer : 1 | Consumer : 2 | Display : 3 | Exit : 0 || 1

Producer
Enter data: 11

Selection
Producer : 1 | Consumer : 2 | Display : 3 | Exit : 0 || 3

Display
buf[0] = 11

Selection
Producer : 1 | Consumer : 2 | Display : 3 | Exit : 0 || 2

Consumer
Consume data: 4196464

如果在消费者块中添加睡眠语句,则获得预期的输出(在我们的例子中为 11)。
由于sleep语句的插入,相比switch的case 2语句,消费者线程有足够的时间来完成它的执行并提供预期的输出。

【问题讨论】:

  • 能否请您更具体地说明问题?
  • 是的 - 怎么会有同步问题?您创建 PC 队列,然后创建生产者/消费者。
  • 另请注意:对于多个生产者/消费者安全的有界 PC 队列,您需要两个信号量和一个互斥量(或三个信号量)或等效的 condvar。

标签: c linux multithreading pthreads producer-consumer


【解决方案1】:

问题在于您的主线程运行到显示消费者线程应该“返回”的数据的地步。但是主线程和消费者之间没有同步。

最简单的解决方案(仍然使用线程)是让主线程加入消费者线程 - 这就是它可以知道消费者已完成其工作的方式。而不是调用睡眠,尝试:

pthread_join(con_t, NULL);

您实际上与producer() 线程有类似的同步问题,只是它并不明显,因为在获得更多输入之前您不会对生产线程更新的数据做任何事情。因此,竞态条件有足够的时间以产生您期望的结果的方式完成。

但是,请记住,您的程序实际上并没有利用并发性 - 它创建线程,但不会并行执行任何重要的工作。您不妨直接致电producer()consumer()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多