go使用条件变量实现生产者消费者模型

概述

前面已经学习过使用channel完成简单的生产者消费者模型了,但那种模型存在一定的弊端,生产者消费者数量增加时,数据容易紊乱或被堵塞,而使用条件变量实现的生产者消费者模型可以有效解决这一点。

所需知识点

条件变量:条件变量的作用并不保证在同一时刻仅有一个协程(线程)访问某个共享的数据资源,而是在对应的共享数据的状态发生变化时,通知阻塞在某个条件上的协程(线程)。条件变量不是锁,在并发中不能达到同步的目的,因此条件变量总是配合锁一起使用

上代码之前我们首先需要知道其中重要的一个难点,即条件变量对应的三个常用方法Wait(),Signal(),Broadcast().

1) func (c *Cond) Wait()
该函数的作用可归纳为如下三点:
a) 阻塞等待条件变量满足
b) 释放已掌握的互斥锁相当于cond.L.Unlock()。注意:两步为一个原子操作
所谓的原子操作的意思是以上两步操作不可分离,一旦启动即两步同时执行。
c) 当被唤醒,Wait()函数返回时,解除阻塞并重新获取互斥锁。相当于cond.L.Lock()

2) func (c *Cond) Signal()
单发通知,给一个正等待(阻塞)在该条件变量上的goroutine(线程)发送通知。

3) func (c *Cond) Broadcast()
广播通知,给正在等待(阻塞)在该条件变量上的所有goroutine(线程)发送通知。
//一般情况下不使用broadcast,会引起惊群!所以我们下面使用Signal函数
理解以上知识点后,再来理解条件变量的使用就比较容易了,上代码:

代码

package main

import (
    "sync"
    "math/rand"
    "time"
    "fmt"
)

var cond sync.Cond//创建全局条件变量

func producter(ch chan<- int)  {
    for  {
        cond.L.Lock()    //go进程进来后,不多比比,先上锁
        for len(ch)==3 { /*注意这里是for而不是if,判断缓冲
区里是不是有太多数据,如果满了,则持续阻塞,直至对面发来signal信号*/
            cond.Wait()
        }
            num:=rand.Intn(1000)
            ch<-num
            fmt.Println("已生产",num)
            cond.L.Unlock()//生产完毕后解锁并给对面发信号
            cond.Signal()
            time.Sleep(time.Millisecond*300)
    }
}
func consumer(ch <-chan int)  {
    for  {
        cond.L.Lock()//以下都是跟上面一样的   
        for len(ch)==0 { 
            cond.Wait()
        }
        num:=<-ch
        fmt.Println("已消费:",num)
        cond.L.Unlock()
        cond.Signal()
        time.Sleep(time.Millisecond*300)
    }
}
func main() {
//给全局变量加上一个锁的功能,相当于给他加个装备
    cond.L=new(sync.Mutex)
    var ch chan int=make(chan int,3)
    var quit chan string
    rand.Seed(time.Now().UnixNano())
    for i:=0;i<5 ;i++  {
        go producter(ch)
    }
    for i:=0;i<3 ;i++  {
        go consumer(ch)
    }
    <-quit//这个管道是故意阻塞在这里,防止主进程结束
}

有问题的小伙伴可以给我留言哦

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Linux中,可以使用C语言的条件变量和线程来实现消费者-生产者模型。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int count = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_prod = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_cons = PTHREAD_COND_INITIALIZER; void *producer(void *arg) { int item = 0; while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区已满,则等待消费者消费 while (count == BUFFER_SIZE) { pthread_cond_wait(&cond_prod, &mutex); } buffer[count] = item; count++; printf("Producer produced item %d\n", item); // 唤醒消费者线程 pthread_cond_signal(&cond_cons); pthread_mutex_unlock(&mutex); item++; } pthread_exit(NULL); } void *consumer(void *arg) { while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区为空,则等待生产者生产 while (count == 0) { pthread_cond_wait(&cond_cons, &mutex); } int item = buffer[count - 1]; count--; printf("Consumer consumed item %d\n", item); // 唤醒生产者线程 pthread_cond_signal(&cond_prod); pthread_mutex_unlock(&mutex); } pthread_exit(NULL); } int main() { pthread_t producer_thread, consumer_thread; // 创建生产者消费者线程 pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); // 等待线程结束 pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); return 0; } ``` 在上面的代码中,生产者线程不断地向缓冲区中生产数据,而消费者线程不断地从缓冲区中消费数据。当缓冲区满时,生产者线程会等待条件变量`cond_prod`,直到有消费者消费数据才会被唤醒。同样,当缓冲区为空时,消费者线程会等待条件变量`cond_cons`,直到有生产者生产数据才会被唤醒。 需要注意的是,在生产者消费者线程之间共享的变量`count`和`buffer`需要进行互斥访问,因此使用互斥锁`mutex`来保护共享资源的访问。 希望这个示例能帮助你理解如何在Linux中使用C语言的条件变量和线程实现消费者-生产者模型

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值