记一次由虚假唤醒产生的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. 刨根问底系列(1)——虚假唤醒(spurious wakeups)的原因以及在pthread_cond_wait、pthread_cond_singal中使用while的必要性

    刨根问底之虚假唤醒 1. 概要 将会以下方式展开介绍: 什么是虚假唤醒 什么原因会导致虚假唤醒(两种原因) 为什么系统内核不从根本上解决虚假唤醒这个"bug"(两个原因) 开发者如 ...

  2. notify丢失、虚假唤醒

    notify丢失: 假设线程A因为某种条件在条件队列中等待,同时线程B因为另外一种条件在同一个条件队列中等待,也就是说线程A/B都被同一个Object.wait()挂起,但是等待的条件不同. 现在假设 ...

  3. pthread_cond_wait虚假唤醒

    pthread_cond_wait中的while()不仅仅在等待条件变量前检查条件cond_is_false是否成立,实际上在等待条件变量后也检查条件cond_is_false是否成立.在多线程等待的 ...

  4. JUC虚假唤醒(六)

    为什么条件锁会产生虚假唤醒现象(spurious wakeup)? ​ 在不同的语言,甚至不同的操作系统上,条件锁都会产生虚假唤醒现象.所有语言的条件锁库都推荐用户把wait()放进循环里: whil ...

  5. (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁

    8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...

  6. Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。

    模拟通过线程实现消费者和订阅者模式: 首先,定义一个店员:店员包含进货.卖货方法:其次,定义一个生产者,生产者负责给店员生产产品:再者,定义一个消费者,消费者负责从店员那里消费产品. 店员: /** ...

  7. 多线程编程中条件变量和的spurious wakeup 虚假唤醒

    1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...

  8. java多线程 生产者消费者案例-虚假唤醒

    package com.java.juc; public class TestProductAndConsumer { public static void main(String[] args) { ...

  9. 什么是虚假唤醒 spurious wakeup

    解释一下什么是虚假唤醒? 说具体的例子,比较容易说通. pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; v ...

  10. 【转】pthread_cond_signal 虚假唤醒问题

    引用:http://blog.csdn.net/leeds1993/article/details/52738845 什么是虚假唤醒? 举个例子,我们现在有一个生产者-消费者队列和三个线程. I.1号 ...

随机推荐

  1. CF1045G AI robots题解

    题目链接:洛谷 或者 CF 本题考虑转化为 cdq 分治模型 对于 cdq 分治来说,只需要考虑左边对右边的影响,那我们要考虑该怎样设置第一维度的左右对象.很显而易见的是抛开 \(q\) 限制而言,我 ...

  2. JVM metaspace思维导图整理

    JDK8中用元空间metaspace代替了永久代perm,原因和其特性简单介绍一下. 思维导图 图中gc log详解链接:https://www.jianshu.com/p/cd34d6f3b5b4 ...

  3. 如何快速获取AWR中涉及到的表

    最近遇到一个很少见的需求,是关于应用测试方面的. 具体来说,这个应用的测试需求要基于一个固定的时间点数据,而且只能测试一轮,再测试就需要还原到测试前状态. 因为我们使用的存储是分层的(热数据在Flas ...

  4. 使用SpeechRecognition进行语音识别

    操作系统 : CentOS7.7.1908_x64 gcc版本 :4.8.5 Python 版本 : 3.6.8 安装语音识别环境: virtualenv -p /usr/bin/python3 py ...

  5. AT_arc125_c [ARC125C] LIS to Original Sequence 题解

    题目传送门 前置知识 贪心 | 构造 解法 对于任意一个未加入序列 \(P\) 的数 \(x<A_{i}(1 \le i \le k-1)\),如果其放在了 \(A_{i}\) 的前面,会导致最 ...

  6. NC51222 Strategic game

    题目链接 题目 题目描述 Bob enjoys playing computer games, especially strategic games, but sometimes he cannot ...

  7. DataGear 使用静态HTML模板制作数据可视化看板

    DataGear 看板提供了导入静态 HTML 模板的功能,使您可以利用已有的任意 HTML 网页资源快速制作数据可视化看板. 首先,您需要准备一套已设置好布局的静态 HTML 模板,其中包含的 HT ...

  8. 【Azure Function App】本地运行的Function发布到Azure上无法运行的错误分析

    问题描述 Azure Function部署后未执行,查看日志发现错误信息: 2023-12-19T11:12:27.145 [Verbose] Host configuration applied.2 ...

  9. 【Azure 服务总线】使用Azure Service Bus 时,出现证书错误: 所使用的证书具有无法验证的信任链

    问题描述 在Azure中连接 Service Bus 服务发送消息时发生证书错误,抛出证书异常消息: 或 The X.509 certificate CN=servicebus.chinaclouda ...

  10. expect tcl 摘录

    目录 部分参考来源说明 例子 expect命令 核心命令有三个 spawn.expect.send 其他expect命令 expect命令的选项 变量 tcl摘录 数据类型 符号 命令 其他说明 部分 ...