linux 生产者消费者模型 信号量(灯) 条件变量
生产者消费者模型:
模型对象:1.生产者(1或多个) 2.消费者(1或多个) 3.容器(商品)
1 /* 2 生产者和消费者模型(粗略版本) 3 生产者未生产 消费者开始消费 发生错误 4 */ 5 #include <stdio.h> 6 #include <pthread.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 //链表 10 struct Node 11 { 12 int num;//数据 13 struct Node * next;//保存下一个结点 14 }; 15 //头结点 16 struct Node * head = NULL; 17 //生产者 18 void * producer(void * arg) 19 { 20 //不断创建新的结点,添加到链表中 21 while(1) 22 { 23 struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型 24 newNode->next = head;//新结点指向头结点 25 head = newNode;//头节点更新 头插法 26 newNode->num = rand() % 1000; 27 printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self()); 28 usleep(100); 29 } 30 return NULL; 31 } 32 //消费者 33 void * customer(void * arg) 34 { 35 while(1) 36 { 37 //保存头节点的指针 38 struct Node * tmp = head; 39 head = head->next; 40 printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self()); 41 free(tmp);//释放结点空间 42 usleep(100); 43 } 44 return NULL; 45 } 46 int main() 47 { 48 //创建5个生产者线程 和 5个消费者线程 容器:链表 49 pthread_t ptids[5],ctids[5]; 50 for(int i = 0; i < 5; i++) 51 { 52 pthread_create(&ptids[i], NULL, producer, NULL); 53 pthread_create(&ctids[i], NULL, customer, NULL); 54 } 55 //线程分离 56 for(int i = 0; i < 5; i++) 57 { 58 pthread_detach(ptids[i]); 59 pthread_detach(ctids[i]); 60 } 61 pthread_exit(NULL);//线程退出 不执行return 0; 子线程不受影响继续执行 62 return 0; 63 }
使用互斥量解决 段错误 问题,但效率低:
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 //创建一个互斥量 6 pthread_mutex_t mutex; 7 //链表 8 struct Node 9 { 10 int num;//数据 11 struct Node * next;//保存下一个结点 12 }; 13 //头结点 14 struct Node * head = NULL; 15 //生产者 16 void * producer(void * arg) 17 { 18 //不断创建新的结点,添加到链表中 19 while(1) 20 { 21 pthread_mutex_lock(&mutex); 22 struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型 23 newNode->next = head;//新结点指向头结点 24 head = newNode;//头节点更新 头插法 25 newNode->num = rand() % 1000; 26 printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self()); 27 pthread_mutex_unlock(&mutex); 28 usleep(100); 29 } 30 return NULL; 31 } 32 //消费者 33 void * customer(void * arg) 34 { 35 while(1) 36 { 37 pthread_mutex_lock(&mutex); 38 //保存头节点的指针 39 struct Node * tmp = head; 40 if(head != NULL) 41 { 42 //有数据 43 head = head->next; 44 printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self()); 45 free(tmp);//释放 46 pthread_mutex_unlock(&mutex); 47 usleep(100); 48 } 49 else 50 { 51 //没有数据 也要解锁 否则会退出循环重复加锁 导致死锁 52 pthread_mutex_unlock(&mutex); 53 } 54 } 55 return NULL; 56 } 57 int main() 58 { 59 //初始化互斥量 60 pthread_mutex_init(&mutex,NULL); 61 //创建5个生产者线程 和 5个消费者线程 容器:链表 62 pthread_t ptids[5],ctids[5]; 63 for(int i = 0; i < 5; i++) 64 { 65 pthread_create(&ptids[i], NULL, producer, NULL); 66 pthread_create(&ctids[i], NULL, customer, NULL); 67 } 68 //线程分离 69 for(int i = 0; i < 5; i++) 70 { 71 pthread_detach(ptids[i]); 72 pthread_detach(ctids[i]); 73 } 74 while(1) 75 { 76 sleep(10);//如果没有while循环 会结束互斥量 77 } 78 pthread_mutex_destroy(&mutex); 79 pthread_exit(NULL);//线程退出 不执行return 0; 子线程不受影响继续执行 80 return 0; 81 }
条件变量(引起阻塞,解除阻塞): 配合互斥量使用 (例如没有商品,消费者可以通知生产者生产商品)
1 /* 2 条件变量的类型 pthread_cond_t 3 int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr); 4 int pthread_cond_destroy(pthread_cond_t * cond); 5 int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex); 6 - 等待, 调用了该函数, 线程会阻塞 7 int pthread_cond_timedwait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex, const struct timespec * restrict abstime); 8 - 等待多长时间, 调用了这个函数,线程会阻塞,直到指定时间结束 9 int pthread_cond_signal(pthread_cond_t * cond); 10 - 唤醒一个或者多个等待的线程 11 int pthread_cond_broadcast(pthread_cond_t * cond); 12 - 唤醒所有的等待的线程 13 */ 14 #include <stdio.h> 15 #include <pthread.h> 16 #include <unistd.h> 17 #include <stdlib.h> 18 //创建一个互斥量 19 pthread_mutex_t mutex; 20 //创建条件变量 21 pthread_cond_t cond; 22 //链表 23 struct Node 24 { 25 int num;//数据 26 struct Node * next;//保存下一个结点 27 }; 28 //头结点 29 struct Node * head = NULL; 30 //生产者 31 void * producer(void * arg) 32 { 33 //不断创建新的结点,添加到链表中 34 while(1) 35 { 36 pthread_mutex_lock(&mutex); 37 struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型 38 newNode->next = head;//新结点指向头结点 39 head = newNode;//头节点更新 头插法 40 newNode->num = rand() % 1000; 41 printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self()); 42 //只要生产了一个,就通知消费者 43 pthread_cond_signal(&cond); 44 pthread_mutex_unlock(&mutex); 45 usleep(100); 46 } 47 return NULL; 48 } 49 //消费者 50 void * customer(void * arg) 51 { 52 while(1) 53 { 54 pthread_mutex_lock(&mutex); 55 //保存头节点的指针 56 struct Node * tmp = head; 57 //判断是否有数据 58 if(head != NULL) 59 { 60 //有数据 61 head = head->next; 62 printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self()); 63 free(tmp);//释放 64 pthread_mutex_unlock(&mutex); 65 usleep(100); 66 } 67 else 68 { 69 //没有数据, 需要等待 70 //当这个函数调用阻塞的时候,会对互斥锁进行解锁, 当不阻塞的时候,继续向下指向, 会重新加锁 71 pthread_cond_wait(&cond, &mutex);//没有商品 传递cond 等待+解锁 有商品生产了 cond变化 重新运行 加锁 下条语句解锁 72 pthread_mutex_unlock(&mutex); 73 } 74 } 75 return NULL; 76 } 77 int main() 78 { 79 //初始化互斥量 80 pthread_mutex_init(&mutex,NULL); 81 //初始化条件变量 82 pthread_cond_init(&cond,NULL); 83 //创建5个生产者线程 和 5个消费者线程 容器:链表 84 pthread_t ptids[5],ctids[5]; 85 for(int i = 0; i < 5; i++) 86 { 87 pthread_create(&ptids[i], NULL, producer, NULL); 88 pthread_create(&ctids[i], NULL, customer, NULL); 89 } 90 //线程分离 91 for(int i = 0; i < 5; i++) 92 { 93 pthread_detach(ptids[i]); 94 pthread_detach(ctids[i]); 95 } 96 while(1) 97 { 98 sleep(10);//如果没有while循环 会结束互斥量 99 } 100 pthread_mutex_destroy(&mutex); 101 pthread_cond_destroy(&cond); 102 pthread_exit(NULL);//线程退出 不执行return 0; 子线程不受影响继续执行 103 return 0; 104 }
信号量(灯):用于阻塞线程(灯亮表明资源可用,灯灭表明资源不可用)(不能保证线程数据安全,配合互斥锁使用)
1 /* 2 信号量: semaphore 3 信号量的类型 sem_t 4 int sem_init(sem_t * sem, int pshared, unsigned int value); 5 - 初始化信号量 6 - 参数 7 - sem: 信号量变量的地址 8 - pshared: 0:用在线程间, 非0:用在进程间 9 - value: 信号量中的值 10 int sem_destroy(sem_t * sem); 11 - 释放资源 12 int sem_wait(sem_t * sem); 13 - 对信号加锁 ,调用一次对信号量的值 -1, 如果值为0, 就阻塞 14 int sem_trywait(sem_t * sem); 15 int sem_timedwait(sem_t * sem, const struct timespec * abs_timeout); 16 int sem_post(sem_t * sem); 17 - 解锁一个信号量,调用一次对信号量的值 +1 18 int sem_getvalue(sem_t * sem, int * sval); 19 20 sem_t psem; 21 sem_t csem; 22 init(psem, 0, 8); //8是初始量 生产者的限制值 生产调用减少同时产生商品 消费调用增加同时消费商品 23 init(csem, 0, 0); //消费者为0 24 producer() 25 { 26 sem_wait(&psem);//调用 -1 27 sem_post(&csem);// +1 28 } 29 customer() 30 { 31 sem_wait(&csem); 32 sem_post(&psem); 33 } 34 */ 35 #include <stdio.h> 36 #include <pthread.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <semaphore.h> 40 //创建一个互斥量 41 pthread_mutex_t mutex; 42 //创建两个信号量 43 sem_t psem;//生产者信号量 44 sem_t csem;//消费者信号量 45 //链表 46 struct Node 47 { 48 int num;//数据 49 struct Node * next;//保存下一个结点 50 }; 51 //头结点 52 struct Node * head = NULL; 53 //生产者 54 void * producer(void * arg) 55 { 56 //不断创建新的结点,添加到链表中 57 while(1) 58 { 59 sem_wait(&psem);//初始量为8, psem - 1 60 pthread_mutex_lock(&mutex); 61 struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));//malloc一个结点转化为结构体指针类型 62 newNode->next = head;//新结点指向头结点 63 head = newNode;//头节点更新 头插法 64 newNode->num = rand() % 1000; 65 printf("add node,num: %d, itd:%ld\n",newNode->num,pthread_self()); 66 pthread_mutex_unlock(&mutex); 67 sem_post(&csem);//csem + 1 68 usleep(100); 69 } 70 return NULL; 71 } 72 //消费者 73 void * customer(void * arg) 74 { 75 while(1) 76 { 77 sem_wait(&csem);//csem - 1 78 pthread_mutex_lock(&mutex); 79 //保存头节点的指针 80 struct Node * tmp = head; 81 head = head->next; 82 printf("delete node, num : %d, itd %ld\n",tmp->num,pthread_self()); 83 free(tmp);//释放 84 pthread_mutex_unlock(&mutex); 85 sem_post(&psem);//psem + 1 86 usleep(100); 87 } 88 return NULL; 89 } 90 int main() 91 { 92 //初始化互斥量 93 pthread_mutex_init(&mutex,NULL); 94 //初始化信号量 95 sem_init(&psem, 0, 8); 96 sem_init(&csem, 0, 0); 97 //创建5个生产者线程 和 5个消费者线程 容器:链表 98 pthread_t ptids[5],ctids[5]; 99 for(int i = 0; i < 5; i++) 100 { 101 pthread_create(&ptids[i], NULL, producer, NULL); 102 pthread_create(&ctids[i], NULL, customer, NULL); 103 } 104 //线程分离 105 for(int i = 0; i < 5; i++) 106 { 107 pthread_detach(ptids[i]); 108 pthread_detach(ctids[i]); 109 } 110 while(1) 111 { 112 sleep(10);//如果没有while循环 会结束互斥量 113 } 114 pthread_mutex_destroy(&mutex); 115 pthread_exit(NULL);//线程退出 不执行return 0; 子线程不受影响继续执行 116 return 0; 117 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)