生产者消费者问题,是操作系统中的互斥问题。缓冲区是临界资源,每个运行实体(进程或线程)的访问缓冲区的代码是临界区。要确保最多只能有一个人访问临界资源,否则可能会出问题。
生产者或消费者可以有一个或多个。生产者每次生产一个产品,并试图放入缓冲区,如果缓冲区满,则等待。消费者每次试图从缓冲区拿一个产品并消费,如果缓冲区空,则等待。
任何进程在操作缓冲区时,会加锁,此时如果有其它进程试图访问,需要等待当前进程操作完成并释放锁。
C 语言实现 TODO
pthread 库实现了对线程的支持,编译时需要通过 -pthread
参数指定加载此库。
// 创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
// 阻塞等待线程结束,成功结束时立刻返回0
int pthread_join(pthread_t thread, void **retval);
// 退出当前线程
void pthread_exit(void *retval);
golang 实现
golang 作为一门高级语言,内置的 channel 类型可以实现线程安全。当然也可以用 Mutex 加锁来实现。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var buffer chan int
var buf_size int = 3
func main() {
fmt.Println("main start")
buffer = make(chan int, buf_size)
wg.Add(2)
go producer()
go consumer()
fmt.Println("all running")
wg.Wait()
fmt.Println("main end")
}
func producer() {
for i := 0; i < buf_size * 5; i++ {
fmt.Printf("producer make %d product\n", i)
if len(buffer) == buf_size {
fmt.Printf("====buffer full===\n")
}
buffer <- i
fmt.Printf("producer put %d product\n", i)
}
fmt.Println("producer end")
wg.Done()
}
func consumer() {
for i := 0; i < buf_size * 5; i++ {
fmt.Printf("\t\t\tconsumer consume %d product\n", i)
if len(buffer) == 0 {
fmt.Printf("\t\t\t====buffer empty===\n")
}
fmt.Printf("\t\t\tconsumer get %d product\n", <-buffer)
}
fmt.Println("\t\t\tconsumer end")
wg.Done()
}