前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >while 如何解决虚假唤醒 及 if 为什么就不行?

while 如何解决虚假唤醒 及 if 为什么就不行?

作者头像
看、未来
发布2021-10-09 11:40:53
3170
发布2021-10-09 11:40:53
举报
文章被收录于专栏:CSDN搜“看,未来”

希望打开这篇能对你有所帮助。

文章目录

这个问题其实第一次接触虚假唤醒就有答案了,但是当时太拽,留下张图啥也不讲明白,导致现在又不知道是为什么了。。。

看了好久的网上的解说,也都是点到为止,哎,还有些写个“生产消费者”都写不明白,哎。


在这里插入图片描述
在这里插入图片描述

生产·消费者模型示例

1、这段代码不是用来看懂的 2、因为不了解生产·消费者模型,那怎么理解虚假唤醒啊?或者有没有掌握其它条件变量使用场景啊? 3、这段代码只是用来回忆一下,加讲解。

代码语言:javascript
复制
#include <iostream>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;

int current = 0;  // producer运行加1,consumer运行减1
int buf[10];
int in = 0, out = 0;
int items = 0, spaces = 10;
bool flag;  // 标记线程结束运行
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t notfull = PTHREAD_COND_INITIALIZER;  // 缓冲区不满
pthread_cond_t notempty = PTHREAD_COND_INITIALIZER;  // 缓冲区不空

void *producer( void *arg ) {
    while( flag ) {
        pthread_mutex_lock( &mutex );  // 为保证条件变量不会因为多线程混乱,所以先加锁
        while( !spaces ) {  // 避免“惊群”效应,避免因其他线程实现得到事件而导致该线程“假醒”
            pthread_cond_wait( &notfull, &mutex );
        }
        buf[in] = current++;
        in = ( in + 1 ) % 10;
        items++;
        spaces--;

        printf( "producer %zu , current = %d\n", pthread_self(), current );
        for( int i = 0; i < 10; i++ ) {
            printf( "%-4d", buf[i] );
        }
        printf( "\n\n" );

        pthread_cond_signal( &notempty );
        pthread_mutex_unlock( &mutex );
    }
    pthread_exit( NULL );
}

void *consumer( void *arg ) {
    while( flag ) {
        pthread_mutex_lock( &mutex );
        while( !items ) {
            pthread_cond_wait( &notempty, &mutex );
        }
        buf[out] = -1;
        out = ( out + 1 ) % 10;
        current--;
        items--;
        spaces++;

        printf( "consumer %zu , current = %d\n", pthread_self(), current );
        for( int i = 0; i < 10; i++ ) {
            printf( "%-4d", buf[i] );
        }
        printf( "\n\n" );

        pthread_cond_signal( &notfull );
        pthread_mutex_unlock( &mutex );
    }
    pthread_exit( NULL );
}

int main() {
    memset( buf, -1, sizeof(buf) );
    flag = true;
    pthread_t pro[10], con[10];
    int i = 0;

    for( int i = 0; i < 10; i++ ) {
        pthread_create( &pro[i], NULL, producer, NULL );
        pthread_create( &con[i], NULL, consumer, NULL );
    }

    sleep(1);  // 让线程运行一秒
    flag = false;

    for( int i = 0; i < 10; i++ ) {
        pthread_join( pro[i], NULL );
        pthread_join( con[i], NULL );
    }

    return 0;
} 

使用 if 的代码流程

运行,运行,运行,三个线程都走到了 wait 这一步了。 为什么?因为条件变量进入了wait会释放锁啊。

现在都进来了哈。

这时候一个唤醒,肯定只有一个线程拿到了锁,因为锁只有一把,但是被唤醒的就不止是一个线程了。那没拿到锁的线程呢? 没拿到,就没拿到呗,继续往下呗,还想怎么样?

继续往下怎样?没有资源消费呗。脾气不好的线程就 core dump呗。 脾气好点呢?那你两次 unlock() 是没问题吗?

不过哈,这个虚假唤醒呐,没那么点背,触发概率不高,所以人家就懒的修复咯,性价比不高嘛,用户自己解决吧。


使用 while 的代码流程

运行,运行,运行,三个线程都走到了 wait 这一步了。 为什么?因为条件变量进入了wait会释放锁啊。

现在都进来了哈。

这时候,就算三个都给唤醒了,剩下那俩也得再兜回去继续趴着 wait 去。因为 while 是圆的。


这样子可明白?

对了,顺带说一句,条件变量的学名叫管程,别下次人家问管程还反问一句管程是啥,丢人。。。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/09/20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 生产·消费者模型示例
  • 使用 if 的代码流程
  • 使用 while 的代码流程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档