sem_init重复调用引发sem_wait线程无法被唤醒
问题
一段老代码,两个线程,一个线程调用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之后,加入了判断,就有问题了;
结论
- sem_init是用来在初始化的时候调用初始化信号量的,并不是用来将信号量清零的;
- 重复调用sem_init的行为可能导致已经处于sem_wait的线程无法被唤醒;
- 旧版本的glibc机制比较弱,所以老代码一直运行很好;但是新glibc作了检查,所以会出问题;
- 按照目前代码看,如果单个线程自己在调用了sem_wait之后再调用sem_init时没什么影响的;但是不保证以后的glibc会再做什么修改造成影响;
- 除了初始化阶段,其他流程中不要使用sem_init;
- 最好使用其他方式替代信号量,比如条件变量;
sem_init重复调用引发sem_wait线程无法被唤醒的更多相关文章
- Python threading 单线程 timer重复调用函数
项目中需要使用定时器,每次都使用构造器函数调用: timer = threading.Timer(timerFlag, upload_position) timer.start() 打印线程后发现,每 ...
- Fragmen横竖屏切换,导致页面混乱,oncreateView重复调用
在清单文件Activity设置属性 android:screenOrientation="landscape" android:configChanges="screen ...
- Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)
QThread实例代表一个线程,我们可以重新实现QThread::run(),要新建一个线程,我们应该先继承QThread并重新实现run()函数. 需要注意的是: 1.必须在创建QThread对象之 ...
- 关于ListView中getView被重复调用的问题
我用ListView显示数据时,自定义了一个适配器(extends ArrayAdapter),然后重写了getView方法,现在出现一个问题,就是这个getView()方法被重复调用了,比如我的_d ...
- Unity延迟和重复调用方法
延迟调用方法 Invoke(arg1,arg2) arg1 是延迟调用的字符串方法名,arg2是延迟多少时间调用arg1 方法. 重复调用方法 InvokeRepeating(arg1,arg2,ar ...
- 解决FTPClient linux环境下FTPClient调用retrieveFileStream导致线程挂起(防火墙问题);下载文件小于实际文件问题
FTPClient调用retrieveFileStream导致线程挂起(防火墙问题):下载文件小于实际文件问题解决 实际是因为FTP的两种传输模式:主动模式和被动模式的不同而导致的 FTPClient ...
- Android ListView getView()方法重复调用导致position错位
问题现状:Android ListView getView()方法重复调用导致position错位 解决办法:把ListView布局文件的layout_height属性改为fill_parent或者m ...
- FeignClient spi 调用 短路异常 & 线程池配置
FeignClient spi 调用 短路异常 & 线程池配置 默认配置见:HystrixThreadPoolProperties 线程池对象:com.netflix.hystrix.Hyst ...
- JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
一.前言 在多线程的场景下,我们会经常使用加锁,来保证线程安全.如果锁用的不好,就会陷入死锁,我们以前可以使用Object的wait/notify来解决死锁问题.也可以使用Condition的awai ...
随机推荐
- mysql的左连接问题
之前写过一个mysql语句,功能是将一个表ds的一个字段值同步更新到另一个表bk的字段,不过不是全部,只更新表bk中有的数据,如果表bk中有而表ds中没有,表B对应的这个字段值就为空 UPDATE b ...
- Spring Boot 笔记 (8) - H2 数据库
Maven 依赖 <dependency> <groupId>com.h2database</groupId> <artifactId>h2</a ...
- python之set集合、深浅copy初识、join()和fromkeys() 的用法
一.set集合 特点: set集合是无序的,所以不存在索引. set集合中的每个元素都是不重复的. set集合中的每个元素都是可哈希的. 有增删改查操作: 1. 增加 add 当添加的内容重复时 ...
- linux系统编程之信号(一)
今天起,开始新的知识的学习,对于上个系列进程的学习还差一个理论上的总结,这个会下次补回来,以便通过实践之后,再用理论将其巩固一下,好了,话不多说,开始进入这个主题的学习----信号,很重要,但不是太容 ...
- Analysis of algorithms: introduction
一系列的人物角色 Programmer,client,theoretician和blocking 学生可能会承担里面的一个或者多个角色 Running time 提出running time这个概念的 ...
- PL/sql配置相关
可以安装oracle之后,打开PL/sql之后,自动找到oracle的路径以及数据库连接. 或者:安装oracle客户端,手动在PL/sql中配置oic以及oracle主目录的位置,并且配置好C: ...
- Windows窗体控件实现内容拖放(DragDrop)功能
一.将控件内容拖到其他控件 在开发过程中,经常会有这样的要求,拖动一个控件的数据到另外一个控件中.例如将其中一个ListBox中的数据拖到另一个ListBox中.或者将DataGridView中的数据 ...
- c#嵌套CMD窗口
解决方法一: 自己放一个文本框,改成黑色,然后输入命令,执行时,你Process.Start cmd ,此时CMD窗口不显示,然后,将CMD的返回值,再取出来,设回文本框. 如何用这种方法实时获取cm ...
- 在golang中使用json
jsoniter高性能json库 非常快,支持java和go marshal使用的一些坑 package main import ( "encoding/json" "f ...
- Kubernetes 学习7 Pod控制器应用进阶2
一.容器探测器 1.所谓的容器探测无非就是我们在里面设置了一些探针,或者称之为传感器来获取相应的数据作为判定其存活与否或就绪与否的标准,目前k8s所支持的存活性和就绪性探测方式都是一样的. 2.k8s ...