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