作者:崔晓兵从一个线上问题说起
Important: It is generally a good idea to leave the priorities of your threads at their default values. Increasing the priorities of some threads also increases the likelihood of starvation among lower-priority threads. If your application contains high-priority and low-priority threads that must interact with each other, the starvation of lower-priority threads may block other threads and create performance bottlenecks.苹果的建议是不要随意修改线程的优先级,尤其是这些高低优先级线程之间存在临界资源竞争的情况。所以删除相关优先级设置代码即可解决问题。
Realtime applications may encounter priority inversion when using read-write locks. The problem occurs when a high priority thread “locks” a read-write lock that is about to be “unlocked” by a low priority thread, but the low priority thread is preempted by a medium priority thread. This scenario leads to priority inversion; a high priority thread is blocked by lower priority threads for an unlimited period of time. During system design, realtime programmers must take into account the possibility of this kind of priority inversion. They can deal with it in a number of ways, such as by having critical sections that are guarded by read-write locks execute at a high priority, so that a thread cannot be preempted while executing in its critical section.尽管针对的是实时系统,但是还是有一些启示和帮助。按照提示,对有问题的代码进行了修改:在线程通过pthread_rwlock_wrlock拿到_rwlock的时候,临时提升其优先级,在释放_rwlock之后,恢复其原先的优先级。
值得注意的是,这里只能使用pthread的api,NSThread提供的API是不可行的Demo 验证
这里的任务也可以理解为线程
priority ceiling protocol和priority inheritance都会在释放锁的时候,恢复低优先级任务的优先级。同时要注意,以上2种方法只能阻止Unbounded priority inversion,而无法阻止Bounded priority inversion(Task H必须等待Task L执行完毕才能执行,这个反转是无法避免的)。可以通过以下几种发生来避免或者转移Bounded priority inversion:
优先级继承必须是可传递的。举个栗子:当T1阻塞在被T2持有的资源上,而T2又阻塞在T3持有的一个资源上。如果T1的优先级高于T2和T3的优先级,T3必须通过T2继承T1的优先级。否则,如果另外一个优先级高于T2和T3,小于T1的线程T4,将抢占T3,引发相对于T1的优先级反转。因此,线程所继承的优先级必须是直接或者间接阻塞的线程的最高优先级。如何避免优先级反转?
测试验证环境:模拟器 iOS15.2pthread mutex
Caveats: Beware of priority inversion when using read-write locks. A high-priority thread may be blocked waiting on a read-write lock locked by a low-priority thread. The microkernel has no knowledge of read-write locks, and therefore can’t boost the low-priority thread to prevent the priority inversion.大意是内核不感知读写锁,无法提升低优先级线程的优先级,从而无法避免优先级反转。通过查询定义发现:pthread_rwlock_s包含了字段rw_tid,专门来记录持有写锁的线程,这不由令人好奇:为什么pthread_rwlock_s有owner信息却仍然无法避免优先级反转?
xnu supports priority inheritance through “turnstiles”, a kernel-internal mechani** which is used by default by a number of locking primitives (list at [1]), including normal pthread mutexes (though not read-write locks [2]), as well as the os_unfair_lock API (via the ulock syscalls). With pthread mutexes, you can actually explicitly request priority inheritance by calling pthread_mutexattr_setprotocol [3] with PTHREAD_PRIO_INHERIT; the Apple implementation supports it, but currently ignores the protocol setting and just gives all mutexes priority inheritance.大意是:XNU使用turnstiles内核机制进行优先级继承,这种机制被应用在pthread mutex和os_unfair_lock上。
pthread mutexes and rwlocks both (at least sometimes) know their owner and can use turnstiles. Otherwise, we pass NULL as the tstore to the shims so they wait on the global waitq.
值得注意的是,dispatch_wait是一个宏(C11的泛型),或者是一个入口函数,它可以接受dispatch_block_t,dispatch_group_t,dispatch_semaphore_t 3种类型的参数,但是这里的具体含义应该是指dispatch_block_wait,只有dispatch_block_wait会调整优先级,避免优先级反转。
Semaphores are for signaling (sames a condition variables, events) while mutexes are for mutual exclusion. Technically, you can also use semaphores for mutual exclusion (a mutex can be thought as a binary semaphore) but you really shouldn’t.Right, but libdispatch doesn’t have a mutex. It has semaphores and queues. So if you’re trying to use libdispatch and you don’t want the closure-based aspect of queues, you might be tempted to use a semaphore instead. Don’t do that, use os_unfair_lock or pthread_mutex (or a higher-level construct like NSLock) instead.这些是一些警示,可以看到dispatch_semaphore十分危险,使用需要特别小心。
另外,dispatch_group 跟 semaphore 类似,在调用 enter() 方法时,无法预知谁会调用 leave(),所以系统也无法知道其 owner是谁,所以同样不会有优先级提升的问题。信号量卡死现身说法
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |