我正在尝试以线程安全的方式控制网络事件指示器。
这是我目前正在做的方式,但我认为必须有更好的方式来做到这一点。我一直在寻找使用锁,但这似乎是一项昂贵的操作。我一直在研究 OSAtomicAdd,但不知道在这种情况下如何使用它。
+ (void)start
{
[self counterChange:1];
}
+ (void)stop
{
[self counterChange:-1];
}
+ (void)counterChangeNSUInteger)change
{
static NSUInteger counter = 0;
static dispatch_queue_t queue;
if (!queue) {
queue = dispatch_queue_create("NetworkActivityIndicator Queue", NULL);
}
dispatch_sync(queue, ^{
if (counter + change <= 0) {
counter = 0;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
} else {
counter += change;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
});
}
如何使用 OSAtomicAdd 完成这样的事情?
Best Answer-推荐答案 strong>
你不能单独依赖像 OSAtomicAdd 这样的东西来同步这种操作。整个操作需要被锁定以确保它成功运行。
考虑 this answer 中建议的解决方案,这基本上归结为:
static volatile int32_t NumberOfCallsToSetVisible = 0;
int32_t newValue = OSAtomicAdd32((setVisible ? +1 : -1), &NumberOfCallsToSetVisible);
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisiblenewValue > 0)];
如果从一个线程调用此代码,并且将 setVisible 设置为 YES ,则对 OSAtomicAdd32 的调用会将 OSAtomicAdd32 加 1 code>NumberOfCallsToSetVisible 导致 newValue 被设置为 1。
现在考虑如果该线程在执行下一行之前被抢占,并且另一个线程调用该函数并将 setVisible 设置为 NO 会发生什么情况。这次对 OSAtomicAdd32 的调用将从 NumberOfCallsToSetVisible 中减去 1,导致 newValue 设置为 0。
如果第二个线程继续执行,并且下一行被执行,newValue 不大于零,所以 setNetworkActivityIndicatorVisible 方法将被调用 NO 。此时事件指示器仍然不可见,所以这没有任何作用,但也不会造成任何伤害。
但是,最终我们将切换回第一个线程,其中 newValue 设置为 1。所以当该线程执行下一行时,newValue 显然是大于零,setNetworkActivityIndicatorVisible 方法将被调用 YES ,使事件指示器可见。
所以我们在 setVisible 设置为 YES 的情况下调用了一次函数,并在 setVisible 设置为 NO 的情况下再次调用了该函数。您会期望这会导致事件指示器不可见,但事实并非如此。事实上,如果没有其他调用,它将永远保持可见。这显然是不对的。
最重要的是,您需要将整个东西包装在 @synchronize block 或类似的东西中。
关于iphone - Objective-C 线程安全计数器,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/17176190/
|