条件变量是用于多线程/多进程间同步,是一种典型的睡眠唤醒用法。P1等待某个事件的发生,P2触发事件,唤醒P1。
条件变量在初始化时,可以通过接口pthread_condattr_setpshared指定该条件变量可用于进程内的线程间同步,还是用于进程间同步。
但是,在linux的glibc实现中,进程间同步却存在着一个缺陷。将导致问题扩散,非常严重。原因如下:
pthread_cond_t结构体是一个复杂的数据结构,包含了等待信息,多个进程都可能同时调用等待函数pthread_cond_wait/pthread_cond_timedwait,
唤醒函数pthread_cond_signal/pthread_cond_broadcast,为了防止一个或者多个等待者、唤醒者同时操作pthread_cond_t的成员,必须进行互斥.。
所以,pthread_cond_t里还有一个锁。接口实现上,pthread_cond_wait/pthread_cond_timedwait,pthread_cond_signal/pthread_cond_broadcast
都必须先获取锁,然后操作数据,完毕释放锁。
在多进程上,如果某个进程在pthread_cond_xxx的接口里获取了锁以后,因某种原因退出了(比如某个线程运行异常了)。
那么,悲剧来了,锁没有释放。于是,其他的进程只要调用到这个条件变量的接口,将因为获取不到锁而等待,且一直等待下去。
一个进程的异常导致所有进程的异常。
令人困惑的是,mutex也可用于进程间互斥,pthread_mutex_setpshared设置。但是pthread_mutex_t却支持这种场景,进程获取到了mutex后复位了,
没有释放锁,OS帮忙释放(需要在mutex初始化时设置pthread_mutexattr_setrobust_np)。
同样可用于进程间的条件变量为什么没有这个机制?
难道这就是大教堂与大集市的区别。大集市下各种实现,没有一种统一的策略或者机制,保证对外呈现的一致性?
条件变量另外一个让人困惑或者说问题的地方是 这个超时等待接口pthread_cond_timedwait。
通过该接口调用者可以指定一段超时时间,如果超时时间内没有被唤醒则返回,表示这段时间内条件不满足。
但问题是,pthread_cond_timedwait里面获取锁的时间并没有超时。
如果pthread_cond_timedwait接口里获取锁的时间超过了传入的超时时间,那么,返回给调用者的超时时间是不准的,而且难以评估。