多线程|pc2.c 使用信号量解决生产者、计算者、消费者问题

1.题目要求

使用信号量解决生产者、计算者、消费者问题

  • 功能和前面的实验相同,使用信号量解决

2.解决思路

生产者、计算者、消费者三个线程的逻辑与上一题使用条件变量解决生产者、计算者、消费者问题相同,不同之处在于本题使用条件变量实现信号量sema_tvalue记录了信号量的值。sema_wait函数如果信号量的值小于等于0,则等待条件变量将信号量的值减一。sema_signal函数将信号量的值加一,唤醒等待条件变量的线程。定义mutex_sema用于互斥访问共享缓冲区变量in/outempty_buffer_sema/full_buffer_sema用于线程同步(对buffer1buffer2分别定义上述若干个变量)。在main函数中进行sema_init初始化操作,在生产者、计算者、消费者线程函数中可以直接调用sema_waitsema_signal进行申请信号量和释放信号量。

3.代码

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

#define CAPACITY 4
#define ITEM_COUNT 8
int buffer1[CAPACITY], buffer2[CAPACITY];
int in1, in2;
int out1, out2;

typedef struct {
  int value;
  pthread_mutex_t mutex;
  pthread_cond_t cond;
} sema_t;
sema_t mutex1_sema, mutex2_sema;
sema_t empty_buffer1_sema, empty_buffer2_sema;
sema_t full_buffer1_sema, full_buffer2_sema;


// buffer1
int buffer1_is_empty() {
  return in1 == out1;
}

int buffer1_is_full() {
  return (in1 + 1) % CAPACITY == out1;
}

int get_item1() {
  int item = buffer1[out1];
  out1 = (out1 + 1) % CAPACITY;
  return item;
}

void put_item1(int item) {
  buffer1[in1] = item;
  in1 = (in1 + 1) % CAPACITY;
}

// buffer2
int buffer2_is_empty() {
  return in2 == out2;
}

int buffer2_is_full() {
  return (in2 + 1) % CAPACITY == out2;
}

int get_item2() {
  int item = buffer2[out2];
  out2 = (out2 + 1) % CAPACITY;
  return item;
}

void put_item2(int item) {
  buffer2[in2] = item;
  in2 = (in2 + 1) % CAPACITY;
}


// sema
void sema_init(sema_t *sema, int value) {
  sema->value = value;
  pthread_mutex_init(&sema->mutex, NULL);
  pthread_cond_init(&sema->cond, NULL);
}

void sema_wait(sema_t *sema) {
  pthread_mutex_lock(&sema->mutex);
  while(sema->value <= 0)
    pthread_cond_wait(&sema->cond, &sema->mutex);
  --sema->value;
  pthread_mutex_unlock(&sema->mutex);
}

void sema_signal(sema_t *sema) {
  pthread_mutex_lock(&sema->mutex);
  ++sema->value;
  pthread_cond_signal(&sema->cond);
  pthread_mutex_unlock(&sema->mutex);
}


// 生产者
void *produce(void *arg) {
  int item, i;

  for(i = 0; i < ITEM_COUNT; i++) {
    sema_wait(&empty_buffer1_sema);
    sema_wait(&mutex1_sema);

    item = 'a' + i;
    printf("produce item: %c\n", item);
    put_item1(item);

    sema_signal(&mutex1_sema);
    sema_signal(&full_buffer1_sema);
  }
  return NULL;
}

// 计算者
void *compute(void *arg) {
  int item, i;

  for(i = 0; i < ITEM_COUNT; i++) {
    sema_wait(&full_buffer1_sema);
    sema_wait(&mutex1_sema);
    
    item = get_item1();
    printf("\t\tcompute item before: %c\n", item);
    item = item - 32;
    printf("\t\tcompute item after : %c\n", item);

    sema_signal(&mutex1_sema);
    sema_signal(&empty_buffer1_sema);

    sema_wait(&empty_buffer2_sema);
    sema_wait(&mutex2_sema);
    
    put_item2(item);

    sema_signal(&mutex2_sema);
    sema_signal(&full_buffer2_sema);
  }
  return NULL;
}

// 消费者
void *consume(void *arg) {
  int item, i;

  for(i = 0; i < ITEM_COUNT; i++) {
    sema_wait(&full_buffer2_sema);
    sema_wait(&mutex2_sema);
    
    item = get_item2();
    printf("\t\t\t\t\tconsume item: %c\n", item);

    sema_signal(&mutex2_sema);
    sema_signal(&empty_buffer2_sema);
  }
  return NULL;
}


int main() {
  pthread_t computer_tid, consumer_tid;

  sema_init(&mutex1_sema, 1);
  sema_init(&mutex2_sema, 1);
  sema_init(&empty_buffer1_sema, CAPACITY - 1);
  sema_init(&empty_buffer2_sema, CAPACITY - 1);
  sema_init(&full_buffer1_sema, 0);
  sema_init(&full_buffer2_sema, 0);

  pthread_create(&computer_tid, NULL, compute, NULL);
  pthread_create(&consumer_tid, NULL, consume, NULL);
  produce(NULL);
  pthread_join(computer_tid, NULL);
  pthread_join(consumer_tid, NULL);

  return 0;
}

4.运行结果

$ gcc pc2.c -lpthread
$ ./a.out 
produce item: a
produce item: b
produce item: c
                compute item before: a
                compute item after : A
                compute item before: b
                compute item after : B
                compute item before: c
                compute item after : C
                                        consume item: A
                                        consume item: B
                                        consume item: C
produce item: d
produce item: e
produce item: f
                compute item before: d
                compute item after : D
produce item: g
				compute item before: e
                compute item after : E
                compute item before: f
                compute item after : F
                compute item before: g
                compute item after : G
produce item: h
										consume item: D
                                        consume item: E
                                        consume item: F
                compute item before: h
                compute item after : H
                                        consume item: G
                                        consume item: H
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用信号量解决生产者消费者问题C语言代码: ``` #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define BUFFER_SIZE 10 // 缓冲区大小 #define PRODUCER_NUM 2 // 生产者数量 #define CONSUMER_NUM 2 // 消费者数量 sem_t sem_empty, sem_full, sem_mutex; // 三个信号量 int buffer[BUFFER_SIZE]; // 缓冲区 int in = 0, out = 0; // 缓冲区的读写指针 void *producer(void *arg) { int id = *((int *) arg); while (1) { int item = rand() % 100; sem_wait(&sem_empty); // 等待空缓冲区 sem_wait(&sem_mutex); // 互斥访问缓冲区 buffer[in] = item; printf("Producer %d produced item %d\n", id, item); in = (in + 1) % BUFFER_SIZE; sem_post(&sem_mutex); sem_post(&sem_full); // 发送一个满缓冲区信号 sleep(rand() % 3); // 生产者随机休眠 } } void *consumer(void *arg) { int id = *((int *) arg); while (1) { sem_wait(&sem_full); // 等待满缓冲区 sem_wait(&sem_mutex); // 互斥访问缓冲区 int item = buffer[out]; printf("Consumer %d consumed item %d\n", id, item); out = (out + 1) % BUFFER_SIZE; sem_post(&sem_mutex); sem_post(&sem_empty); // 发送一个空缓冲区信号 sleep(rand() % 3); // 消费者随机休眠 } } int main() { pthread_t producers[PRODUCER_NUM]; pthread_t consumers[CONSUMER_NUM]; int producer_ids[PRODUCER_NUM]; int consumer_ids[CONSUMER_NUM]; int i; sem_init(&sem_empty, 0, BUFFER_SIZE); // 初始化空缓冲区信号量 sem_init(&sem_full, 0, 0); // 初始化满缓冲区信号量 sem_init(&sem_mutex, 0, 1); // 初始化互斥信号量 // 创建生产者线程 for (i = 0; i < PRODUCER_NUM; i++) { producer_ids[i] = i; pthread_create(&producers[i], NULL, producer, &producer_ids[i]); } // 创建消费者线程 for (i = 0; i < CONSUMER_NUM; i++) { consumer_ids[i] = i; pthread_create(&consumers[i], NULL, consumer, &consumer_ids[i]); } // 等待生产者线程结束 for (i = 0; i < PRODUCER_NUM; i++) { pthread_join(producers[i], NULL); } // 等待消费者线程结束 for (i = 0; i < CONSUMER_NUM; i++) { pthread_join(consumers[i], NULL); } sem_destroy(&sem_empty); // 销毁信号量 sem_destroy(&sem_full); sem_destroy(&sem_mutex); return 0; } ``` 该程序中使用了三个信号量:`sem_empty`表示空缓冲区数量,`sem_full`表示满缓冲区数量,`sem_mutex`表示互斥访问缓冲区。 在生产者线程中,当缓冲区为空时,使用`sem_wait(&sem_empty)`等待空缓冲区;当缓冲区不为空时,使用`sem_post(&sem_full)`发送一个满缓冲区信号。在生产者向缓冲区中写入数据时,必须先使用`sem_wait(&sem_mutex)`进行互斥访问缓冲区,写入数据后再使用`sem_post(&sem_mutex)`释放互斥信号量。 在消费者线程中,当缓冲区满时,使用`sem_wait(&sem_full)`等待满缓冲区;当缓冲区不满时,使用`sem_post(&sem_empty)`

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值