保护关键代码不被再次调用

发布于 2024-12-16 14:12:49 字数 737 浏览 1 评论 0原文

我需要保护代码的关键区域,该区域是多线程的。我想防止在另一个线程完成之前多次调用它。这就是我正在处理的内容:

- (void) filterAllEventsIntoDictionary{

    // start critical area
    if (self.sortedKeys.count != 0) {
        [self.sortedKeys removeAllObjects];
    }
    dispatch_async(self.filterMainQueue, ^{

        [self internal_filterAllEventsIntoDictionary]; 

        dispatch_sync(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    });
}

由于 internal_filterAllEventsIntoDictionary 方法也访问 self.sortedKeys,如果此代码被调用两次,它会因为 removeAllObjects 而崩溃> 在开始时。

我仍然需要在另一个线程中调用 internal... 方法,因为我不想阻止 UI。那么,在 dispatch_async 调用尚未完成时阻止此方法开始的最佳方法是什么?

I need to protect a critical area of my code, which is multi-threaded. I want to prevent it from being called multiple times before the other thread is finished. This is what I am working with:

- (void) filterAllEventsIntoDictionary{

    // start critical area
    if (self.sortedKeys.count != 0) {
        [self.sortedKeys removeAllObjects];
    }
    dispatch_async(self.filterMainQueue, ^{

        [self internal_filterAllEventsIntoDictionary]; 

        dispatch_sync(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    });
}

Since the internal_filterAllEventsIntoDictionary method also accesses self.sortedKeys, if this code is called twice, it crashes because of removeAllObjects at the start.

I still need to call the internal... method in another thread since I don't want to block the UI. So what's the best way to block on the start of this method while the dispatch_async call is still not finished?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

难如初 2024-12-23 14:12:49

虽然我远不是并发专家,但在我看来,您需要锁定您的 sortedKeys 对象。但是,如果您使用传统的锁,您最终会阻塞主线程。

在 Grand Central Dispatch 的世界中,推荐的锁替代方案是将代码的关键部分放在串行队列上。请参阅 “消除基于锁的代码”

如果您将 [self.sortedKeys removeAllObjects]; 调用放入具有 internal... 调用的块所安排的同一队列上,那么您保证它不会直到该块完成之后才会发生:

// start critical area
dispatch_async(self.filterMainQueue, ^{
    if (self.sortedKeys.count != 0) {
        [self.sortedKeys removeAllObjects];
    }
});

这假设 filterMainQueue串行。对临界区使用dispatch_async可以确保主线程不会被阻塞。另请注意 "调度队列和线程安全"

请勿从传递给函数调用的同一队列上执行的任务中调用 dispatch_sync 函数。这样做会导致队列死锁。

尽管只有当 internal... 方法执行某些操作导致再次调用该方法时,这才会成为问题。

While I am far from being a concurrency expert, it sounds to me like you need a lock on your sortedKeys object. If you used a traditional lock, though, you'd end up blocking the main thread.

The recommended replacement for locks in the world of Grand Central Dispatch is to put critical sections of code on a serial queue. See "Eliminating Lock-Based Code" in the Concurrency Programming Guide.

If you put the [self.sortedKeys removeAllObjects]; call onto the same queue that the block with the internal... call is scheduled on, you guarantee that it won't happen until after that block completes:

// start critical area
dispatch_async(self.filterMainQueue, ^{
    if (self.sortedKeys.count != 0) {
        [self.sortedKeys removeAllObjects];
    }
});

This assumes that filterMainQueue is serial. Using dispatch_async for the critical section ensures that the main thread will not be blocked. Also note the warning in "Dispatch Queues and Thread Safety":

Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue.

Although this will only be an issue if the internal... method does something that causes this method to be called again.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文