#include <stdio.h>
#include <pthread.h>//pthread_create()函数的头文件
#include <windows.h>//sleep的头文件
#define N 10
#define true 1
#define sleepTime 1000//1000就是1S
#define producerNum 10
#define consumerNum 10
typedef int semaphore;
typedef int item;
item buffer[N] = {0}; //缓冲池的情况
int in = 0; //生产者的指针
int out = 0; //消费者的指针
semaphore mutex = 1; //互斥性信号量
semaphore empty = N; //空着的缓冲区数
semaphore full = 0; //有东西的缓冲区数
void *producer(void *a) {
while (true) {
while (empty <= 0) {
printf("缓冲区已满!\n");
}
empty--;//执行P操作
while (mutex <= 0); //判断是否能进入缓冲区(mutex=1可入)
mutex--;//进行P操作
buffer[in] = 1; //生产完缓冲区设置为1
in = (in + 1) % N; //是环形存储为了防止出现假溢出的现象
mutex++;//执行V操作
full++;//上下两步可调整先后
Sleep(sleepTime);
//当我们设置sleep时,等于告诉cpu,当前的线程不再运行,持有当前对象的锁。
//那么这个时候cpu就会切换到另外的线程了。这种操作有些时候是非常好的。
}
}
void *consumer(void *b) {
while (true) {
while (full <= 0) {
printf("缓冲区为空!\n");
}
full--;//执行P操作
while (mutex <= 0);
mutex--;
int nextc = buffer[out];
buffer[out] = 0; //消费完将缓冲区设置为0
out = (out + 1) % N;
mutex++;
empty++;
printf("消费一个产品ID%d,缓冲区位置为%d\n", nextc, out);
Sleep(sleepTime);
}
}
int main() {
//创建进程池,就是所有进程都能放进去的一个线程组
pthread_t threadPool[producerNum + consumerNum];
int i;
for (i = 0; i < producerNum; i++) {
pthread_t temp;
//pthread_t是一个表示线程的数据类型
//pthread_create是用来创建线程的
if (pthread_create(&temp, NULL, producer, NULL) == -1) {
//pthread_create的第一个参数是指向线程标识符的指针
//第二个参数是用来设置线程的属性(一般不用设置所以一般为NULL)
//第三个参数是线程运行函数的起始地址(就是新建线程需要执行的函数,该函数的参数最多有 1 个(可以省略不写))
//第四个参数是运行函数的参数
printf("ERROR, fail to create producer%d\n", i);
exit(1);
}
threadPool[i] = temp;
}//创建生产者线程放入线程池
for (i = 0; i < consumerNum; i++) {
pthread_t temp;
if (pthread_create(&temp, NULL, consumer, NULL) == -1) {
printf("ERROR, fail to create consumer%d\n", i);
exit(1);
}
threadPool[i + producerNum] = temp;
}//创建消费者线程放入线程池
void *result;
for (i = 0; i < producerNum + consumerNum; i++) {
if (pthread_join(threadPool[i], &result) == -1) {
printf("fail to recollect\n");
exit(1);
}
}//运行线程池
return 0;
}