返回

多线程情境中 CFRunloop 安全吗?

IOS

很多人在讨论CFRunloop时,都会强调它的线程安全特性。然而,事情往往并没有那么简单。CFRunloop在多线程环境中,尤其是在停止runloop时,存在着安全隐患。虽然苹果官方也承认了这一点,但他们仅仅用了一个模糊的词语“generally”来这种不安全性。

/*
 * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Software License Terms.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/* Block until the specified run loop exits.
 * Only guaranteed to work for the current run loop, or the run loop of a thread
 * that is calling CFRunLoopRun, and generally only if no other threads are
 * modifying the run loop state (adding/removing sources or observers).
 */
CF_EXPORT
void CFRunLoopWait(CFRunLoopRef rl, CFTimeInterval seconds);

在实际编程中,CFRunloop多线程隐患主要是出现在停止runloop时,因为此时runloop的状态是可能会被其他线程修改的。举个例子,假设我们有一个线程A负责管理runloop,而线程B负责向runloop中添加新的source。当线程A调用CFRunLoopStop时,线程B可能刚好也在向runloop中添加source,这就会导致runloop的状态发生变化,从而引发安全问题。

为了避免这种安全隐患,我们可以使用如下几种解决方案:

  • 使用互斥锁来保护runloop的状态。在停止runloop之前,先获得互斥锁,然后停止runloop,最后释放互斥锁。这样就可以确保在停止runloop时,不会有其他线程对runloop的状态进行修改。
  • 使用CFRunLoopPerformBlock函数来停止runloop。CFRunLoopPerformBlock函数会在runloop的下一个循环中执行指定的block,因此我们可以使用这个函数来安全地停止runloop。
  • 使用CFRunLoopRunInMode函数来停止runloop。CFRunLoopRunInMode函数会一直运行runloop,直到指定的mode结束,因此我们可以使用这个函数来安全地停止runloop。

总之,虽然CFRunloop是线程安全的,但在多线程环境中停止runloop时,存在着安全隐患。我们可以使用互斥锁、CFRunLoopPerformBlock函数或CFRunLoopRunInMode函数来避免这种安全隐患。