声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正 尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处
Objective-C 提供了对线程同步以及异常绑定( )的支持。要打开对这些特性的支持。可以使用GCC3.3以及更新版本 -fobjc-exceptions
开关。
注意: 这个开关只有在 Mac OS X v10.3 以及更新的版本中才能使用,因为对异常处理以及同步的运行时支持在早前的版本中还没有出现
Objective-C 支持多线程。因此,两个线程可以在同时去改变同一个对象,这时就可能在程序中产生问题。为了避免一段代码在运行时被多个线程操作, Objective-C 提供了 @synchronized()
指令.
@synchronized()
指令会为一段代码加锁以在同一时间确保只有一个线程可以使用。其它的线程被锁定直到当前获得锁的线程退出受保护的代码。
@synchronized()
指令只有一个参数,可以是任何 Objective-C 对象, 包括 self
. 这个对象被称为互斥信号量. 它允许一个线程锁定一个代码块以防止同一时间被其它线程访问。你应该使用不同的信号来保护程序的不同的临界区。最安全的方法就是在产生多线程的状况之前创建好所有需要的互斥信号对象,以防止出现紊乱状况。
11-1 展示了使用 self
来作为当前对象的实例方法同步访问的信号量。与此类似,你可以使用类对象为相关类的类方法进行同步保护。在后面一种情况中,同一时间只会有一个线程可以执行这个类方法,因为对于所有的调用者来说,都只有一个类对象可被使用。
- (void)criticalMethod |
{ |
@synchronized(self) { |
// Critical code. |
... |
} |
} |
11-2 展示了一个更常用的方式。在执行一个关键流程时,代码从 Account
类中获得了一个信号量并用它来锁定该关键流程快。 Account
类可以在它的initialize
方法中创建该信号量.
Account *account = [Account accountFromString:[accountField stringValue]]; |
// Get the semaphore. |
id accountSemaphore = [Account semaphore]; |
@synchronized(accountSemaphore) { |
// Critical code. |
... |
} |
Objective-C 的同步特性支持可迭代和可重入代码。一个线程可以在一个可迭代情况下多次使用单个信号量。其它的线程则被锁住直到占有锁的线程释放锁,即当 @synchronized()
块正常退出或者通过异常退出后。
当在 @synchronized()
块中的代码抛出一个异常时, Objective-C 运行时会捕获这个异常,释放该信号量 (这样被保护的代码即可以被其它线程执行), 并再次抛出该异常给下一个异常处理器。
Threading
Objective-C provides support for thread synchronization and exception handling, which are explained in this chapter and in To turn on support for these features, use the -fobjc-exceptions
switch of the GNU Compiler Collection (GCC) version 3.3 and later.
Note: Using either of these features in a program renders the application runnable only in Mac OS X v10.3 and later because runtime support for exception handling and synchronization is not present in earlier versions of the software.
Objective-C supports multithreading in applications. Therefore, two threads can try to modify the same object at the same time, a situation that can cause serious problems in a program. To protect sections of code from being executed by more than one thread at a time, Objective-C provides the @synchronized()
directive.
The @synchronized()
directive locks a section of code for use by a single thread. Other threads are blocked until the thread exits the protected code—that is, when execution continues past the last statement in the@synchronized()
block.
The @synchronized()
directive takes as its only argument any Objective-C object, including self
. This object is known as a mutual exclusion semaphore or mutex. It allows a thread to lock a section of code to prevent its use by other threads. You should use separate semaphores to protect different critical sections of a program. It’s safest to create all the mutual exclusion objects before the application becomes multithreaded, to avoid race conditions.
Listing 11-1 shows code that uses self
as the mutex to synchronize access to the instance methods of the current object. You can take a similar approach to synchronize the class methods of the associated class, using the class object instead of self
. In the latter case, of course, only one thread at a time is allowed to execute a class method because there is only one class object that is shared by all callers.
Locking a method using self
- (void)criticalMethod |
{ |
@synchronized(self) { |
// Critical code. |
... |
} |
} |
Listing 11-2 shows a general approach. Before executing a critical process, the code obtains a semaphore from the Account
class and uses it to lock the critical section. The Account
class could create the semaphore in itsinitialize
method.
Locking a method using a custom semaphore
Account *account = [Account accountFromString:[accountField stringValue]]; |
// Get the semaphore. |
id accountSemaphore = [Account semaphore]; |
@synchronized(accountSemaphore) { |
// Critical code. |
... |
} |
The Objective-C synchronization feature supports recursive and reentrant code. A thread can use a single semaphore several times in a recursive manner; other threads are blocked from using it until the thread releases all the locks obtained with it; that is, every @synchronized()
block is exited normally or through an exception.
When code in an @synchronized()
block throws an exception, the Objective-C runtime catches the exception, releases the semaphore (so that the protected code can be executed by other threads), and rethrows the exception to the next exception handler.