【问题标题】:Thread safety in method with asynchronous operations具有异步操作的方法中的线程安全
【发布时间】:2014-12-21 05:32:44
【问题描述】:

我有这个方法

- (void) checkIfShouldSendReadingsToServerAsync
    {
    // Check if I want to send the data
    // All other threads should wait hear until I signal them to continue
    if (!self.lastSendRequestToServerDateTime ||
        ([[NSDate date] timeIntervalSinceDate:self.lastSendRequestToServerDateTime]/60.0) > intervalBetweenRequestsToServerInMinutes.doubleValue)
        {
        // Read data from the SQLite database asynchronous and a completion block
        // This call uses a NSOperationQueue block
        [self.sqliteStore readingsToSendToServer:^(NSArray *readingsArray)
            {
            // Loaded the values, now check if I should send them
            if (readingsArray &&
                readingsArray.count > 0)
                {
                // Convert array of objects to JSON
                NSString* json = [self.sqliteStore readingsArrayToJSON:readingsArray];
                // Send the JSON to the server using NSURLSession
                [[WEEServiceRepository sharedInstance] sendJSONReadings:json withCompletionHandler:^(NSError *error, NSURLResponse *response)
                    {
                    // REST POST call ended, check the status code
                    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
                    NSInteger statusCode = httpResponse.statusCode;
                    self.lastSendRequestToServerDateTime = [NSDate date];
                    switch (statusCode)
                        {
                        case 200:
                        case 201:
                        case 204:
                            {
                            // This call uses a NSOperationQueue block
                            [self.sqliteStore updateReadingsWithSentToServerYes:readingsArray andCompletionBlock:^(BOOL succeed)
                                {
                                // Here allow all other threads or the same thread to enter
                                }];
                                break;
                            }
                        default:
                            {
                            // Or here signal to continue
                            }
                        }
                    }];
                }
            }];
        }
    }

我希望整个方法是线程安全的,直到服务调用返回并发出信号表明其他线程可以继续执行之前,它应该让它们保持一致。

此代码将在应用程序处于前台但也处于后台时运行。 我尝试了信号量,但一段时间后我发现它在后台停止,可能是死锁?但它不应该!我真的不想使用@synchronized,还是我错了继续尝试?也许只使用 NSLock 或 NSRecursiveLock?

我试图找到最合适的方式来锁定和解锁代码段,尤其是在使用异步方法时。

【问题讨论】:

  • NSLock 是更好的选择
  • 看起来是这样,如果我也将此方法包装在 NSOperationQueue 块中并使用 pthread 互斥锁而不是 NSLock 包装器,您会怎么看?我会获得优化和速度吗? Mutex 似乎比 NSLock 快 50%。
  • 另外,似乎 NSLock 需要从被锁定的同一个线程中解锁,这在我的情况下是不可能的。
  • 这里不完全清楚你在同步什么。也许您可以更新问题中的代码示例,并显示您想象的资源被锁定和解锁的位置。 (您关于从不同线程锁定和解锁的评论让我感到困惑。)就@synchronizedNSLock 而言,这并没有让我觉得有足够的争用很重要,但在这些情况下,自旋锁、GCD 串行队列和读写器模式通常更有效。
  • 好的,让我说得更清楚一点,我想锁定读数ToSendToServer:^(NSArray *readingsArray),在我完成 REST 调用和/或更新它们之前,没有人应该阅读这些资源.

标签: ios objective-c multithreading asynchronous


【解决方案1】:

当您必须在this example 的帮助下处理一系列依赖的异步操作时,我确保了线程安全,从 NSOperation 重写并实现属性 isExecuting、isFinished 和 start 方法可以让您控制何时释放队列操作并继续下一个操作,在我的例子中将 NSOperationQueue.maxConcurrentOperationCount 设置为 1。

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 2016-06-08
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多