问题

一段老代码,两个线程,一个线程调用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. vue环境搭建及创建项目

    安装node环境:node环境下载地址:https://nodejs.org/zh-cn/download/,可根据对应的操作系统版本下载安装 安装完成后查看对应的node和npm版本,如没有出现对应 ...

  2. [daily] 使用thunderbird通过davmail代理访问Microsoft Exchange Service(OWA)

    前言 我需要接入某企业的邮件服务器, 该服务器没有开通pop3, 没有smtp, 没有imap, 只有exchange. 也就是说必须要使用outlook才能访问. 但是我没有outlook. 方案一 ...

  3. Linux操作系统的文件查找工具locate和find命令常用参数介绍

    Linux操作系统的文件查找工具locate和find命令常用参数介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.非实时查找(数据库查找)locate工具  locate命 ...

  4. python高级特性-列表生成

    概述 [x *x for x in range(1,11)][k+'='+v for k,v in d.items()] [s.lower() for s in L] 详解 1.单层迭代 >&g ...

  5. 可观测委托与map委托原理详解

    在上一次https://www.cnblogs.com/webor2006/p/11369333.html中学习了委托属性,然后它在实际中有四种使用情况: 接下来则学习一下另外两种属性委托的使用. 可 ...

  6. .net框架-数组(Array)& ArrayList & List

    数组(Array)特点: 初始化时规定长度 元素类型相同 数据存储连续,效率高 System.Collections.ArrayList : 初始化时无需规定长度,长度随存储的数据动态扩充与收缩 元素 ...

  7. service worker(二)之主页面与service worker通信

    实现一个主页面发送消息,worker搜到信息向所有的页面派发消息(当前页面除外) msg.html <!DOCTYPE html> <html lang="en" ...

  8. pycharm 远程修改服务器代码

    首先在本地和服务器上下载pydevd pip3 install pydevd 然后在 设置SSH连接, 出现:java.net.ConnectException:Connection refused ...

  9. Mac上django 报错 [Errno 13] Permission denied: '/static'

    将setting文件中的 改成:

  10. sentinel主从切换技术

    主从切换技术的方法是: 当主服务器宕机后,需要手动把一台从服务器切换为主服务器, 这就需要人工干预,费事费力,还会造成一段时间内服务不可用. 这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式. 一 ...