如果生产者将容器填满,需要通知消费者,
如果消费者将容器清空,需要通知生产者。
(我个人觉得如果有多个生产者和消费者,就排成队列,通知第一个就行。不知道实际情况是什么样子的)
/*
生产者消费者模型(简单版)
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
struct Node
{
int num;
struct Node*next;
};
//头节点
struct Node*head = NULL;
void *producer(void*arg){
//不断的创建新的节点,添加到链表中
while (1)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand()%1000;
printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());
usleep(100);
}
return NULL;
}
void *customer(void*arg){
while (1)
{
//保存头节点的指针
struct Node*tmp = head;
head = head->next;
printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());
free(tmp);
usleep(100);
}
return NULL;
}
int main(void){
pthread_t ptids[5],ctids[5];
for(int i = 0;i < 5;i++){
pthread_create(&ptids[i],NULL,producer,NULL);
pthread_create(&ctids[i],NULL,customer,NULL);
}
for(int i = 0;i < 5;i++){
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
pthread_exit(NULL);
return 0;
}
简单的运行的结果
解决方法:
1)互斥量
2)条件变量,实现线程的通信
如何生成 core 文件?
1、首先查看并更改 core 文件的大小设置
2、在生成的可执行文件中加入可调式信息
在生成了core 文件后,打开 gdb
3、通过使用 core-file (core filename)来打开 core 文件,查看 core 文件当中的内容。
总的来说,上面的程序存在两个问题:1)一个是多个进程操作同一个数据但是没有同步的问题
2)另一个是当 head 为null 的时候会被 costumer 访问 head-> next 的问题。
解决第一个问题:加上互斥量
在这里插入代码片
会发生死锁
解决第二个问题,加上条件变量,生产者生产完成后唤醒消费者,消费者在没有物品的时候等待。
但是依然会死锁,因为没有释放互斥量
/*
条件变量的类型 pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
- 等待,调用了该函数,线程会阻塞
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
- 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间阻塞
int pthread_cond_signal(pthread_cond_t *cond);
- 唤醒一个或者多个等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
- 唤醒所有的等待的线程
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
//创建一个互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;
struct Node
{
int num;
struct Node*next;
};
//头节点
struct Node*head = NULL;
void *producer(void*arg){
//不断的创建新的节点,添加到链表中
while (1)
{
pthread_mutex_lock(&mutex);
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand()%1000;
printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());
//只要生产了一个就通知消费者消费
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
usleep(100);
}
return NULL;
}
void *customer(void*arg){
while (1)
{
//保存头节点的指针
pthread_mutex_lock(&mutex);
struct Node*tmp = head;
//判断是否有数据
if(head != NULL){
head = head->next;
printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());
free(tmp);
pthread_mutex_unlock(&mutex);
usleep(100);
}else{
//没有数据,需要等待
pthread_cond_wait(&cond,&mutex);
//当wait 函数对这个线程进行阻塞的时候,会对这个线程进行解锁,线程不阻塞的时候,会把mutex 互斥量加上去。
//这样就不至于产生影响。
pthread_mutex_unlock(&mutex);
// pthread_mutex_unlock(&mutex);
}
}
return NULL;
}
int main(void){
pthread_t ptids[5],ctids[5];
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
for(int i = 0;i < 5;i++){
pthread_create(&ptids[i],NULL,producer,NULL);
pthread_create(&ctids[i],NULL,customer,NULL);
}
for(int i = 0;i < 5;i++){
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
while (1)
{
sleep(100);
}
//不加 while 死循环会直接执行下面销毁互斥量的语句,那互斥量就没法用了
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_exit(NULL);
// pthread_mutex_destroy(&mutex);
//不能放这里,放这里直接退出了就无法执行了
return 0;
}
使用信号量
/*
信号量的类型 sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 初始化信号量
- 参数
- sem : 信号变量的地址
- pshared : 0 用在线程间,非0 用在进程间
- value : 信号量中的值
int sem_destroy(sem_t *sem);
- 释放资源
int sem_wait(sem_t *sem);
- 对信号量加锁,调用一次对信号量的值减一,如果为0就阻塞。
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
- 对信号量解锁,调用一次对信号量减一
int sem_getvalue(sem_t *sem, int *sval);
sem_t psem;
sem_t csem;
init(psem, 0, 8);
init(csem, 0, 0);
producer() {
sem_wait(&psem);
sem_post(&csem)
}
customer() {
sem_wait(&csem);
sem_post(&psem)
}
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>
//创建一个互斥量
pthread_mutex_t mutex;
sem_t psem;
sem_t csem;
struct Node
{
int num;
struct Node*next;
};
//头节点
struct Node*head = NULL;
void *producer(void*arg){
//不断的创建新的节点,添加到链表中
while (1)
{
sem_wait(&psem);
pthread_mutex_lock(&mutex);
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand()%1000;
printf("add node, num : %d,tid : %ld.\n",newNode->num,pthread_self());
pthread_mutex_unlock(&mutex);
sem_post(&csem);
usleep(100);
}
return NULL;
}
void *customer(void*arg){
while (1)
{
//保存头节点的指针
sem_wait(&csem);
pthread_mutex_lock(&mutex);
struct Node*tmp = head;
//判断是否有数据
head = head->next;
printf("del node,num : %d,tid : %ld.\n",tmp->num,pthread_self());
free(tmp);
pthread_mutex_unlock(&mutex);
sem_post(&psem);
}
return NULL;
}
int main(void){
pthread_t ptids[5],ctids[5];
pthread_mutex_init(&mutex,NULL);
sem_init(&psem,0,8); //表示容器空位
sem_init(&csem,0,0);//表示生产的物品数
for(int i = 0;i < 5;i++){
pthread_create(&ptids[i],NULL,producer,NULL);
pthread_create(&ctids[i],NULL,customer,NULL);
}
for(int i = 0;i < 5;i++){
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
while (1)
{
sleep(100);
}
//不加 while 死循环会直接执行下面销毁互斥量的语句,那互斥量就没法用了
pthread_mutex_destroy(&mutex);
pthread_exit(NULL);
// pthread_mutex_destroy(&mutex);
//不能放这里,放这里直接退出了就无法执行了
return 0;
}
运行结果非常丝滑