线程安全总结(ThreadSafety Summary)

本附录描述OS X和iOS中高级线程安全的一些关键框架。本附录中的信息可能发生变化。Cocoa

Cocoa中多线程使用指南包括以下几点:

不可变对象通常是线程安全的。一旦你创建它们,你可以在线程间安全的传递这些对象。另一方面,可变的对象通常是线程不安全的。在线程应用中使用可变对象,应用必须适当的同步。更多信息,参见可变VS不可变(Mutable Versus Immutable)。

许多视为“线程不安全”的对象只是在多线程中使用不安全。只要一次只有一个线程,很多这些对象可以使用在任何线程中。应用的主线程明确限制调用这类对象。

应用程序的主线程负责处理事件。尽管其他线程包含在事件路径中,应用工具包继续工作,但操作顺序会不对。

如果你想使用线程来绘制视图,把代码放在NSView的lockFocusIfCanDraw和unlockFocus方法之间。

Cocoa中使用POSIX线程,你必须先把Cocoa设为多线程模式。更多信息,参见在Cocoa应用中使用POSIX线程(Using POSIX Threads in a Cocoa Application)。

基础框架线程安全

有一种误解,认为基础框架是线程安全的,应用工具包框架是线程不安全的。不幸的是,这是一个粗略的概括,有些误导。每个框架都有些区域是线程安全的有些区域是线程不安全的。以下章节描述一般线程安全的基础框架。

线程安全的类和函数

以下类和函数通常被认为是线程安全的。你可以在多线程中使用相同实例而不用先获取锁。

(in OS X v10.5and later)线程不安全的类

下面的类和函数通常是线程不安全的。在大多数情况下,只要一次只使用一个线程,你可以在任何线程中使用这些类。查看类文档了解更多细节。

注意:尽管NSSerializer,NSArchiver,NSCoder和NSEnumerator对象本身是线程安全的,它们列在这里是因为在使用它们时,改变它们封装的数据对象是不安全的。例如,在一个文档的情况下,改变已存档的对象图是不安全的。对于一个枚举,任何改变枚举集合的线程都是不安全的。

主线程中使用的类

下面的类必须在应用的主线程中使用。

NSAppleScript可变VS不可变

不可变对象通常是线程安全的,一旦你创建它们,你可以在线程间安全的传递这些对象。当然,使用不可变对象时,你仍然需要记得正确使用引用计数器。如果不当释放一个没有保留的对象,你以后可能会引起异常。

可变对象通常是线程不安全的。在多线程应用中使用可变对象,引用必须使用锁来同步访问它们。(更多信息,参见原子操作(Atomic Operations))。一般来说,集合类与变化有关时(例如,,)是线程不安全的。也就是说,如果一个或多个线程正在改变相同的数组,问题可能会发生。你必须在读写的地方锁定以保证线程安全。

即使一个方法返回一个不可变对象,你永远不应该简单的假定返回的对象是不可变的。根据方法实现,返回的对象可能是可变或不可变的。例如,一个返回类型的方法由于实现,实际返回的是一个。如果你像保证对象是不可变的,你应该构造一个不可变的副本。

可重入

当操作“呼叫”同一个对象或不同对象的其他操作时,可重入是唯一的可能。保留和释放对象是这样的一个“呼叫”,有时会被忽视。

下表列出了部分明确可重入的基础框架。所有其他类可能也可能不是可重入的,或者他们在未来可重入。可重入的完整分析重来没做过,这个列表可能并不详尽。

类初始化

Objective-C运行时系统在类接收到其他消息前,发送一个initialize消息给每个类对象。这样让类在被使用前,建立自己的运行环境。在多线程应用中,运行时保证只有一个线程,线程发送第一个消息给类执行initialize方法。如果另一个线程试图发送消息给类,而这个类仍然在第一个线程的initialize方法中,另一个线程会阻塞直到initialize方法完成执行。与此同时,第一个线程可以继续调用类的其他方法。initialize方法不应该依赖于另一个线程调用类的方法,如果是这样,两个线程都将成为死锁。

由于OS X 10.1.x以及早期版本的bug,在另一个线程执行完类的initialize方法前,一个线程可以发送消息到类。线程可以访问尚未完全初始化的值,可能导致应用崩溃。如果你遇到这个问题,在多线程前,你需要引入锁来防止访问该值直到它们初始化或强制类本身初始化。

自动释放池

每个线程维护自己对象堆栈。Cocoa预计有个自动释放池在当前线程堆栈可用。如果释放池不可用,对象不能被释放,内存泄露。在基于应用工具包应用的主线程中,NSAutoreleasePool对象自动创建和销毁,但次要线程(只有基础框架的应用)必须在使用Cocoa前创建自己创建。如果你的线程是长期的并潜在生成很多自动释放对象,你应该定期销毁并创建自动释放池(如应用工具包在主线程),否则,自动释放对象累积且内存占用增加。如果你的分离线程不使用Cocoa,你不需要创建自动释放池。

运行循环

每个线程有且只有一个运行循环。每次运行循环,因此每个线程都有自己的一组输入模式,这个模式决定当运行循环运行时监听哪些输入源。一个运行循环中定义的输入模式不影响另一个运行循环中定义的输入模式,即使它们肯那个具有相同的名称。

如果你的应用是基于应用工具包,主线程的运行循环自动运行,但次要线程(只有基础框架的应用)必须运行自己的运行循环。如果分离线程不进入运行循环,一旦分离方法执行完成,线程立即退出。

尽管有些外在表现,类是线程不安全的。你必须在拥有它的线程调用这个类的实例方法。

应用工具包框架线程安全

以下章节描述应用工具包框架的通用线程安全。

线程不安全的类

下面的类和函数通常是线程不安全的。在大多数情况下,只要你一次只使用一个线程,你可以在任何线程中使用这些类。更多细节查阅类文档。

NSGraphicsContext。更多信息,参见NSGraphicsContext限制(NSGraphicsContext Restrictions)。NSImage.更多信息,参见NSImage限制(NSImage Restrictions)。NSResponderNSWindow以及其所有的后代。更多信息,参见Window限制(Window Restrictions)。主线程中的类人生最大的错误是不断担心会犯错

线程安全总结(ThreadSafety Summary)

相关文章:

你感兴趣的文章:

标签云: