OGeek|极客世界-中国程序员成长平台

标题: iphone - Objective-C 线程安全计数器 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-13 02:54
标题: iphone - Objective-C 线程安全计数器

我正在尝试以线程安全的方式控制网络事件指示器。

这是我目前正在做的方式,但我认为必须有更好的方式来做到这一点。我一直在寻找使用锁,但这似乎是一项昂贵的操作。我一直在研究 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-推荐答案


你不能单独依赖像 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 不大于零,所以 setNetworkActivityIndi​​catorVisible 方法将被调用 NO。此时事件指示器仍然不可见,所以这没有任何作用,但也不会造成任何伤害。

但是,最终我们将切换回第一个线程,其中 newValue 设置为 1。所以当该线程执行下一行时,newValue 显然是大于零,setNetworkActivityIndi​​catorVisible 方法将被调用 YES,使事件指示器可见。

所以我们在 setVisible 设置为 YES 的情况下调用了一次函数,并在 setVisible 设置为 NO 的情况下再次调用了该函数。您会期望这会导致事件指示器不可见,但事实并非如此。事实上,如果没有其他调用,它将永远保持可见。这显然是不对的。

最重要的是,您需要将整个东西包装在 @synchronize block 或类似的东西中。

关于iphone - Objective-C 线程安全计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17176190/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://sqlite.in/) Powered by Discuz! X3.4