
5.线程与并发同步-生产者消费者信号量模型
发布日期:2021-05-15 09:23:28
浏览次数:24
分类:精选文章
本文共 3671 字,大约阅读时间需要 12 分钟。
进化版的互斥锁(1 --> N) 由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。 信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。
【练习】:使用信号量完成线程间同步,模拟生产者,消费者问题。 【sem_product_consumer.c】
分析: 规定: 如果□中有数据,生产者不能生产,只能阻塞。 如果□中没有数据,消费者不能消费,只能等待数据。 定义两个信号量:S满 = 0, S空 = 1 (S满代表满格的信号量,S空表示空格的信号量,程序起始,格子一定为空) 所以有: T生产者主函数 { T消费者主函数 { sem_wait(S空); sem_wait(S满); 生产… 消费… sem_post(S满); sem_post(S空); } } 假设: 线程到达的顺序是:T生、T生、T消。 那么: T生1 到达,将S空-1,生产,将S满+1 T生2 到达,S空已经为0, 阻塞 T消 到达,将S满-1,消费,将S空+1 三个线程到达的顺序是:T生1、T生2、T消。而执行的顺序是T生1、T消、T生2 这里,S空 表示空格子的总数,代表可占用信号量的线程总数–>1。其实这样的话,信号量就等同于互斥锁。 但,如果S空=2、3、4……就不一样了,该信号量同时可以由多个线程占用,不再是互斥的形式。因此我们说信号量是互斥锁的加强版。 sem_wait函数 给信号量加锁 – 操作,如果为0,则阻塞 int sem_wait(sem_t *sem); sem_post函数 给信号量解锁 ++ 操作 int sem_post(sem_t *sem);#include#include #include #include #include int queue[5];sem_t black,product;//void *producer(void*arg){ int i=0; while(1){ sem_wait(&black); queue[i]=rand()%100+1; printf("produce %d\n",queue[i]); sem_post(&product); i=(i+1)%5; sleep(rand()%2); }}void *conusm(void*arg){ int i=0; while(1){ sem_wait(&product); printf("conusm %d\n",queue[i]); queue[i]=0; sem_post(&black); i=(i+1)%5; sleep(rand()%2); }}int main(){ pthread_t p1,p2; sem_init(&black,0,5); sem_init(&product,0,0); pthread_create(&p1,NULL,producer,NULL); pthread_create(&p2,NULL,conusm,NULL); pthread_join(p1,NULL); pthread_join(p2,NULL); sem_destroy(&black); sem_destroy(&product); return 0;}
@ubuntu:~/Desktop/work/0912$ gcc sem.c -pthread
@ubuntu:~/Desktop/work/0912$ ./a.outproduce 84
conusm 84 produce 16 conusm 16 produce 87 produce 50 conusm 87 produce 28 conusm 50 produce 64 produce 41 produce 73 produce 12 conusm 28 produce 30 conusm 64 produce 63 conusm 41 ^C【推演练习】: 理解上述模型,推演,如果是两个消费者,一个生产者,是怎么样的情况。
#include#include #include #include #include #include using namespace std;queue my_Queue;sem_t black,product;//void *producer(void*arg){ while(1){ sem_wait(&black); int num= rand() % 1000 + 1; //模拟生产一个产品 my_Queue.push (num); //产品入队 printf("---produce %d, now total = %lu\n",num,my_Queue.size()); sem_post(&product); usleep(50); }}void *conusm(void*arg){ srand(time(NULL)); while(1){ sem_wait(&product); int num=my_Queue.front(); //获取队头元素 my_Queue.pop();//出 printf("id: %lu, conusm %d, now total = %lu\n",pthread_self(),num,my_Queue.size()); sem_post(&black); sleep(rand()%2+1); }}int main(){ pthread_t p1,p2[2]; sem_init(&black,0,5); sem_init(&product,0,0); pthread_create(&p1,NULL,producer,NULL); pthread_create(&p2[0],NULL,conusm,NULL); pthread_create(&p2[1],NULL,conusm,NULL); pthread_join(p1,NULL); pthread_join(p2[0],NULL); pthread_join(p2[1],NULL); sem_destroy(&black); sem_destroy(&product); return 0;}
—produce 911, now total = 1
id: 140211254994688, conusm 911, now total = 0 —produce 21, now total = 1 id: 140211263387392, conusm 21, now total = 0 —produce 27, now total = 1 —produce 443, now total = 2 —produce 781, now total = 3 —produce 665, now total = 4 —produce 542, now total = 5 id: 140211263387392, conusm 27, now total = 4 —produce 425, now total = 5 id: 140211254994688, conusm 443, now total = 4 —produce 499, now total = 5 id: 140211254994688, conusm 781, now total = 4 id: 140211263387392, conusm 665, now total = 3 —produce 96, now total = 4 —produce 914, now total = 5 id: 140211254994688, conusm 542, now total = 4 id: 140211263387392, conusm 425, now total = 3 —produce 317, now total = 4 —produce 645, now total = 5发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月18日 22时41分26秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
C++错误笔记
2021-05-13
SpringBoot使用RedisTemplate简单操作Redis的五种数据类型
2021-05-13
qt问题记录-spin box与double spin box
2021-05-13
移动端事件
2021-05-13
spring-day01
2021-05-13
抖音发布黄金时间段,抖音上热门最佳时间
2021-05-13
Thymeleaf sec:authorize 标签不生效
2021-05-14
Iterable与Iterator
2021-05-14
SecSolar:为代码“捉虫”,让你能更专心写代码
2021-05-14
GRUB2
2021-05-14
微信JS-SDK DEMO页面和示例代码
2021-05-14
GridView自定义删除操作
2021-05-14
一张图搞定RPC框架核心原理
2021-05-14
Scala中的包
2021-05-14
他来了他来了,他带着云栖大会的免费门票走来了
2021-05-14
获取linux 主机cpu类型
2021-05-14
Android Studio updating indices 一直刷新和闪烁
2021-05-14
pwntools编写技巧
2021-05-14
How2Heap笔记(三)
2021-05-14