记一次由虚假唤醒产生的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. JuiceFS 新手必知 24 问

    JuiceFS 是一个创新性的软件产品,很多初次尝试的小伙伴对产品和用法感到很多疑惑,所以为了帮助大家快速理解并上手 JuiceFS,我们整理了24个关于 JuiceFS 经典的问题答案,相信经过这 ...

  2. (python)每日代码||2024.1.29||斐波那契数列第i个数函数

    def fib(n): a, b = 0, 1 for _ in range(n): a, b = b, a + b return a

  3. Softmax偏导及BP过程的推导

    Softmax求导 其实BP过程在pytorch中可以自动进行,这里进行推导只是强迫症 A Apart证明softmax求导和softmax的BP过程 本来像手打公式的,想想还是算了,引用部分给出la ...

  4. NC15976 小C的周末

    题目链接 题目 题目描述 愉快的周末到了,小C和他的N-1个朋友买了M个游戏,游戏编号从1~M.每个游戏都是多人游戏,他们打算周末一起打游戏. 小C的每个朋友都决定好了要玩哪一款游戏(会有一组人打同一 ...

  5. Android 自动化测试项目

    1 前言 ​ 在 Android自动化测试框架uiautomator2详解 中,介绍了 uiautomator2 框架的环境配置.元素定位工具以及常用接口. ​ 本文对 uiautomator2 框架 ...

  6. Vue+SpringBoot+ElementUI实战学生管理系统-1.项目介绍

    1.项目介绍 前段时间有位老铁问老徐有没有Vue+SpringBoot+ElementUI前后分离的项目想学习下,抱歉前端时间有点忙.千呼万唤始出来,做得不是很到位,需要的朋友可以拿去自己定制.:) ...

  7. win32- 函数运行速度测试

    LARGE_INTEGER nFreq, t1, t2; int loop_count = 0; double dt; double time_sum = 0; QueryPerformanceFre ...

  8. centos7.5 hadoop NAT 静态IP网络环境搭建

    1 设置 VMware 网络环境 1. 选择VMNet8 并将子网IP 修改为 192.168.10.0,保证集群ip都在这个网段下 2. 选择NAT 设置,配置NAT的网关为 192.168.10. ...

  9. 搭建Windows环境下的多功能免费SSH客户端

    关于Windows下的SSH客户端工具,可以有许多选择,从开源免费到商业收费的,零零总总. 免费版: Putty就是最简单的SSH客户端,非常轻量级. Electerm是一个开源可免费使用的跨平台SS ...

  10. Centos8上安装Redis5.X

    一.下载Redis 下载地址:wget http://download.redis.io/releases/redis-5.0.7.tar.gz 解压:tar -xzvf redis-5.0.7.ta ...