菜鸟教程小白 发表于 2022-12-13 02:54:04

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(&#34;NetworkActivityIndicator Queue&#34;, NULL);
    }
    dispatch_sync(queue, ^{
      if (counter + change &lt;= 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), &amp;NumberOfCallsToSetVisible);
[ setNetworkActivityIndicatorVisible:(newValue &gt; 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>setNetworkActivityIndi​​catorVisible</code> 方法将被调用 <code>NO</code>。此时事件指示器仍然不可见,所以这没有任何作用,但也不会造成任何伤害。</p>

<p>但是,最终我们将切换回第一个线程,其中 <code>newValue</code> 设置为 1。所以当该线程执行下一行时,<code>newValue</code> 显然是大于零,<code>setNetworkActivityIndi​​catorVisible</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]
查看完整版本: iphone - Objective-C 线程安全计数器