记一次由虚假唤醒产生的bug
记一次由虚假唤醒产生的bug
用int a代表产品数量最少0最多10,有两个生产者,三个消费者,用多线程和条件变量模拟生产消费过程:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
//产品0-10
int a = 0;
//条件变量,互斥变量
pthread_cond_t cond_produce, cond_consume;
pthread_mutex_t mutex;
//生产过程
void *produce(void *argv)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(a >= 10)
pthread_cond_wait(&cond_produce, &mutex);
++a;
printf("%s生产后:%d\n",(char*)argv, a);
pthread_cond_signal(&cond_consume);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
//消费过程
void *consume(void *argv)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(a <= 0)
pthread_cond_wait(&cond_consume, &mutex);
// 消费产品
--a;
printf("%s消费后:%d\n",(char*)argv, a);
//唤醒生产者
pthread_cond_signal(&cond_produce);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
//初始化两个生产者和三个消费者
void initiate(pthread_t *producer1, pthread_t *producer2, pthread_t *customer1,
pthread_t *customer2, pthread_t *customer3)
{
pthread_cond_init(&cond_produce, NULL);
pthread_cond_init(&cond_consume, NULL);
pthread_mutex_init(&mutex, NULL);
//两个生产者,三个消费者
pthread_create(producer1, NULL, produce, "生产者1");
pthread_create(producer2, NULL, produce, "生产者2");
pthread_create(customer1, NULL, consume, "消费者1");
pthread_create(customer2, NULL, consume, "消费者2");
pthread_create(customer3, NULL, consume, "消费者3");
pthread_detach(*producer1);
pthread_detach(*producer2);
pthread_detach(*customer1);
pthread_detach(*customer2);
pthread_detach(*customer3);
}
int main() {
pthread_t producer1 = 0, producer2 = 0, customer1 = 0,
customer2 = 0, customer3 = 0;
initiate(&producer1, &producer2, &customer1, &customer2, &customer3);
getchar();
pthread_cond_destroy(&cond_consume);
pthread_cond_destroy(&cond_produce);
pthread_mutex_destroy(&mutex);
return 0;
}
运行结果:
·····
生产者2生产后:11
消费者1消费后:10
消费者1消费后:9
消费者1消费后:8
消费者1消费后:7
消费者1消费后:6
消费者1消费后:5
消费者1消费后:4
消费者1消费后:3
消费者1消费后:2
消费者1消费后:1
消费者1消费后:0
消费者2消费后:-1
发现产品a会超过10也会小于0,刚开始以为pthread_cond_signal()会产生惊群效应,但后来实验了一下并不会,再查资料就知道了虚假唤醒:
维基百科翻译:
当线程从等待已发出信号的条件变量中唤醒时,就会发生虚假唤醒,但发现它正在等待的条件未得到满足。 它被称为虚假的,因为线程似乎无缘无故地被唤醒了.但虚假的唤醒不会无缘无故地发生:它们通常发生是因为,在条件变量发出信号的时间和等待线程最终运行的时间之间,另一个线程运行并更改了条件.线程之间存在争用条件,典型的结果是,有时,在条件变量上唤醒的线程首先运行,赢得比赛,有时它运行第二,输掉比赛。
在许多系统上,特别是多处理器系统上,虚假唤醒的问题会加剧,因为如果在发出信号时有多个线程等待条件变量,系统可能会决定将它们全部唤醒,将每个唤醒一个线程视为唤醒所有线程,从而打破了信号和唤醒之间任何可能预期的1:1关系。 如果有十个线程在等待,则只有一个线程获胜,其他九个线程将经历虚假唤醒。
记一次由虚假唤醒产生的bug的更多相关文章
- 刨根问底系列(1)——虚假唤醒(spurious wakeups)的原因以及在pthread_cond_wait、pthread_cond_singal中使用while的必要性
刨根问底之虚假唤醒 1. 概要 将会以下方式展开介绍: 什么是虚假唤醒 什么原因会导致虚假唤醒(两种原因) 为什么系统内核不从根本上解决虚假唤醒这个"bug"(两个原因) 开发者如 ...
- notify丢失、虚假唤醒
notify丢失: 假设线程A因为某种条件在条件队列中等待,同时线程B因为另外一种条件在同一个条件队列中等待,也就是说线程A/B都被同一个Object.wait()挂起,但是等待的条件不同. 现在假设 ...
- pthread_cond_wait虚假唤醒
pthread_cond_wait中的while()不仅仅在等待条件变量前检查条件cond_is_false是否成立,实际上在等待条件变量后也检查条件cond_is_false是否成立.在多线程等待的 ...
- JUC虚假唤醒(六)
为什么条件锁会产生虚假唤醒现象(spurious wakeup)? 在不同的语言,甚至不同的操作系统上,条件锁都会产生虚假唤醒现象.所有语言的条件锁库都推荐用户把wait()放进循环里: whil ...
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...
- Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。
模拟通过线程实现消费者和订阅者模式: 首先,定义一个店员:店员包含进货.卖货方法:其次,定义一个生产者,生产者负责给店员生产产品:再者,定义一个消费者,消费者负责从店员那里消费产品. 店员: /** ...
- 多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...
- java多线程 生产者消费者案例-虚假唤醒
package com.java.juc; public class TestProductAndConsumer { public static void main(String[] args) { ...
- 什么是虚假唤醒 spurious wakeup
解释一下什么是虚假唤醒? 说具体的例子,比较容易说通. pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; v ...
- 【转】pthread_cond_signal 虚假唤醒问题
引用:http://blog.csdn.net/leeds1993/article/details/52738845 什么是虚假唤醒? 举个例子,我们现在有一个生产者-消费者队列和三个线程. I.1号 ...
随机推荐
- CF1045G AI robots题解
题目链接:洛谷 或者 CF 本题考虑转化为 cdq 分治模型 对于 cdq 分治来说,只需要考虑左边对右边的影响,那我们要考虑该怎样设置第一维度的左右对象.很显而易见的是抛开 \(q\) 限制而言,我 ...
- JVM metaspace思维导图整理
JDK8中用元空间metaspace代替了永久代perm,原因和其特性简单介绍一下. 思维导图 图中gc log详解链接:https://www.jianshu.com/p/cd34d6f3b5b4 ...
- 如何快速获取AWR中涉及到的表
最近遇到一个很少见的需求,是关于应用测试方面的. 具体来说,这个应用的测试需求要基于一个固定的时间点数据,而且只能测试一轮,再测试就需要还原到测试前状态. 因为我们使用的存储是分层的(热数据在Flas ...
- 使用SpeechRecognition进行语音识别
操作系统 : CentOS7.7.1908_x64 gcc版本 :4.8.5 Python 版本 : 3.6.8 安装语音识别环境: virtualenv -p /usr/bin/python3 py ...
- AT_arc125_c [ARC125C] LIS to Original Sequence 题解
题目传送门 前置知识 贪心 | 构造 解法 对于任意一个未加入序列 \(P\) 的数 \(x<A_{i}(1 \le i \le k-1)\),如果其放在了 \(A_{i}\) 的前面,会导致最 ...
- NC51222 Strategic game
题目链接 题目 题目描述 Bob enjoys playing computer games, especially strategic games, but sometimes he cannot ...
- DataGear 使用静态HTML模板制作数据可视化看板
DataGear 看板提供了导入静态 HTML 模板的功能,使您可以利用已有的任意 HTML 网页资源快速制作数据可视化看板. 首先,您需要准备一套已设置好布局的静态 HTML 模板,其中包含的 HT ...
- 【Azure Function App】本地运行的Function发布到Azure上无法运行的错误分析
问题描述 Azure Function部署后未执行,查看日志发现错误信息: 2023-12-19T11:12:27.145 [Verbose] Host configuration applied.2 ...
- 【Azure 服务总线】使用Azure Service Bus 时,出现证书错误: 所使用的证书具有无法验证的信任链
问题描述 在Azure中连接 Service Bus 服务发送消息时发生证书错误,抛出证书异常消息: 或 The X.509 certificate CN=servicebus.chinaclouda ...
- expect tcl 摘录
目录 部分参考来源说明 例子 expect命令 核心命令有三个 spawn.expect.send 其他expect命令 expect命令的选项 变量 tcl摘录 数据类型 符号 命令 其他说明 部分 ...