静态变量可以用作@synchronized参数吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态变量可以用作@synchronized参数吗?相关的知识,希望对你有一定的参考价值。
我们希望保证静态变量的线程安全性。我们在@synchronized指令中使用了另一个静态变量作为对象。像这样:
static NSString *_saveInProgressLock = @"SaveInProgressLock";
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
@synchronized(_saveInProgressLock) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
@synchronized(_saveInProgressLock) {
_saveInProgress = save;
}
}
我们在商店中的应用程序中遇到问题,可以通过阻止_saveInProgress变量设置为NO来重现。你看到上面的代码有什么问题吗?
它与此有何不同?
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
@synchronized([MyClass class]) {
return _saveInProgress;
}
}
+ (void)setSaveInProgress:(BOOL)save {
@synchronized([MyClass class]) {
_saveInProgress = save;
}
}
tl; dr:只要字符串文字是唯一的,这是完全安全的。如果它不是唯一的,则可能存在(良性)问题,但通常仅在发布模式下。但是,可能有一种更简单的方法来实现这一点。
@synchronized
块使用运行时函数objc_sync_enter
和objc_sync_exit
(source)实现。这些函数是使用由指针值键入的全局(但是objc-internal)的锁边表来实现的。在C-API级别,您还可以锁定(void *)42
,或实际上任何指针值。即使对象处于活动状态也无关紧要,因为指针永远不会被解除引用。然而,objc编译器拒绝编译@synchronized(obj)
表达式,如果obj
没有静态类型检查id
类型(其中NSString *
是一个子类型,所以它没关系)并且可能它保留了对象(我不确定),所以你应该只与对象一起使用它。
但有两个关键点需要考虑:
- 如果你同步的
obj
是NULL指针(目标C中的nil
),那么objc_sync_enter
和objc_sync_exit
都是no-ops,这导致了在完全没有锁定的情况下执行块的不良情况。 - 如果对不同的
@synchronized
块使用相同的字符串值,则编译器可能足够智能以将它们映射到相同的指针地址。也许编译器现在不会这样做,但它是Apple可能在未来引入的完全有效的优化。所以你应该确保使用唯一的名称。如果发生这种情况,两个不同的@synchronized
块可能会意外地使用相同的锁,程序员想要使用不同的锁。顺便说一下,你也可以使用[NSObject new]
作为锁定对象。
在类对象([MyClass class]
)上同步是非常安全的,也可以。
现在以更简单的方式。如果你只想要一个原子的BOOL变量,你可以使用无锁编程:
static BOOL _saveInProgress;
+ (BOOL)saveInProgress {
__sync_synchronize();
return _saveInProgress;
}
+ (void)setSaveInProgress:(BOOL)save {
_saveInProgress = save;
__sync_synchronize();
}
这有更好的性能,就像线程安全一样。 qazxsw poi是一个记忆障碍。
但请注意,两种解决方案的安全性取决于您如何使用它们。如果你有一个看起来像这样的保存方法:
__sync_synchronize()
+ (void)save { // line 21
if(![self saveInProgress]) { // line 22
[self setSaveInProgress:YES]; // line 23
// ... do stuff ...
[self setSaveInProgress:NO]; // line 40
}
}
方法根本不是线程安全的,因为第22行和第23行之间存在竞争条件。(不要在这里详细说明..如果您需要更多信息,只需提出一个新问题。)
以上是关于静态变量可以用作@synchronized参数吗?的主要内容,如果未能解决你的问题,请参考以下文章
对象以及变量的并发访问--synchronized的使用细节,用法
可以将 64 位数据类型用作 AdjustWindowRect 的参数吗