问题

一段老代码,两个线程,一个线程调用sem_wait等待信号量,另外一个线程在某失败分支会调用sem_init清信号量,结果导致sem_wait线程无法被唤醒;

分析

Linux manpage

从描述中可见,初始化一个已经被初始化的信号量会导致未定义行为;

 NAME
sem_init - initialize an unnamed semaphore SYNOPSIS
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); Link with -lrt or -pthread. DESCRIPTION
... Initializing a semaphore that has already been initialized results in undefined behavior.

glibc源码

到底会发生什么未定义行为,我们直接看源码吧;

首先,对比结构体,旧结构体只有value成员,新结构体中增加了private和nwaiters成员;nwaiters成员会在调用sem_wait时候增加;

然后,对比sem_post唤醒函数;可见,新唤醒函数会在唤醒操作执行之前对nwaiters进行判断,只有当nwaiters>0时,才进行唤醒;

而旧的唤醒操作,则没有类似判断;

现在,我们清楚了,老代码用的老版本的glibc,内部没有等待判断,一直没有出问题,而使用新版本的glibc之后,加入了判断,就有问题了;

结论

  1. sem_init是用来在初始化的时候调用初始化信号量的,并不是用来将信号量清零的;
  2. 重复调用sem_init的行为可能导致已经处于sem_wait的线程无法被唤醒;
  3. 旧版本的glibc机制比较弱,所以老代码一直运行很好;但是新glibc作了检查,所以会出问题;
  4. 按照目前代码看,如果单个线程自己在调用了sem_wait之后再调用sem_init时没什么影响的;但是不保证以后的glibc会再做什么修改造成影响;
  5. 除了初始化阶段,其他流程中不要使用sem_init;
  6. 最好使用其他方式替代信号量,比如条件变量;

sem_init重复调用引发sem_wait线程无法被唤醒的更多相关文章

  1. Python threading 单线程 timer重复调用函数

    项目中需要使用定时器,每次都使用构造器函数调用: timer = threading.Timer(timerFlag, upload_position) timer.start() 打印线程后发现,每 ...

  2. Fragmen横竖屏切换,导致页面混乱,oncreateView重复调用

    在清单文件Activity设置属性 android:screenOrientation="landscape" android:configChanges="screen ...

  3. Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)

    QThread实例代表一个线程,我们可以重新实现QThread::run(),要新建一个线程,我们应该先继承QThread并重新实现run()函数. 需要注意的是: 1.必须在创建QThread对象之 ...

  4. 关于ListView中getView被重复调用的问题

    我用ListView显示数据时,自定义了一个适配器(extends ArrayAdapter),然后重写了getView方法,现在出现一个问题,就是这个getView()方法被重复调用了,比如我的_d ...

  5. Unity延迟和重复调用方法

    延迟调用方法 Invoke(arg1,arg2) arg1 是延迟调用的字符串方法名,arg2是延迟多少时间调用arg1 方法. 重复调用方法 InvokeRepeating(arg1,arg2,ar ...

  6. 解决FTPClient linux环境下FTPClient调用retrieveFileStream导致线程挂起(防火墙问题);下载文件小于实际文件问题

    FTPClient调用retrieveFileStream导致线程挂起(防火墙问题):下载文件小于实际文件问题解决 实际是因为FTP的两种传输模式:主动模式和被动模式的不同而导致的 FTPClient ...

  7. Android ListView getView()方法重复调用导致position错位

    问题现状:Android ListView getView()方法重复调用导致position错位 解决办法:把ListView布局文件的layout_height属性改为fill_parent或者m ...

  8. FeignClient spi 调用 短路异常 & 线程池配置

    FeignClient spi 调用 短路异常 & 线程池配置 默认配置见:HystrixThreadPoolProperties 线程池对象:com.netflix.hystrix.Hyst ...

  9. JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)

    一.前言 在多线程的场景下,我们会经常使用加锁,来保证线程安全.如果锁用的不好,就会陷入死锁,我们以前可以使用Object的wait/notify来解决死锁问题.也可以使用Condition的awai ...

随机推荐

  1. 笔谈FFmpeg(二)

    经过前面的学习对FFmpeg的基本流程已经很熟悉了,现在到了掌握其中细节的时候了,用FFmpeg做播放器解码操作中,涉及到了一些结构体,这些结构之间到底有什么关系,它们是怎样协同工作的呢.文章 FFM ...

  2. Python学习日记(九) 装饰器函数

    1.import time a.time.time() 获取到当前的时间,返回值为浮点型 import time print(time.time()) #1565422783.6497557 b.ti ...

  3. request-html 简单爬虫

    import asyncio from requests_html import HTMLSession url = 'http://www.xiaohuar.com/hua/' session = ...

  4. js对样式的操作

    本文有:对某个事件的来回操作实现对css样式的来回修改 .比如实现hover效果 <!DOCTYPE html> <html> <head> <meta ch ...

  5. 探索JVM底层奥秘ClassLoader源码分析

    1.JVM基本结构: *.java--------javac编译------>*.class-----ClassLoad加载---->运行时数据区------->执行引擎,接口库-- ...

  6. Linux 永久改变系统时间

    Centos系统,必须同时修改系统时间和硬件时间,才可以保证修改有效,单纯的使用date命令修改系统时间,是立即生效,重启后系统还原.具体操作如下: 1.date {查看目前本地的时间}2.hwclo ...

  7. 清除PLSQL Developer访问数据库连接的历史记录

    1.C盘下 路径: C:\Users\JourneyOfFlower\AppData\Roaming\PLSQL Developer 12\Preferences\JourneyOfFlower\ J ...

  8. oracle删除重复数据,只保留一条

    比如,某个表要按照id和name重复,就算重复数据 delete from 表名 where rowid not in (select min(rowid) from 表名 group by id,n ...

  9. 织梦个人空间中调用ip,会员类型,邮箱,金币,会员积分

    织梦个人空间中调用.用户昵称,最后登录,会员等级 ,会员头衔,会员积分,空间访问,邮箱地址 ,金币数量,会员组的有效期天数 ,升级会员组的时间 ,用户的等级,用户的性别 ,会员的类型,ip 第一步确定 ...

  10. LightOJ - 1336 - Sigma Function(质数分解)

    链接: https://vjudge.net/problem/LightOJ-1336 题意: Sigma function is an interesting function in Number ...