标签: grand-central-dispatch

任何超过 255 秒的任务 GCD 都会崩溃

以下代码会在 iOS 模拟器中产生崩溃。

- (void)viewDidLoad
{
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDate *sleepStart = [NSDate date];
        while ([sleepStart timeIntervalSinceNow] > -300) {

        }
    });    
}
Run Code Online (Sandbox Code Playgroud)

更新:即使在后台线程上也会出现此问题

下面的代码也有错误:

- (void)viewDidLoad
{
    [super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSDate *sleepStart = [NSDate date];
        while ([sleepStart timeIntervalSinceNow] > -300) {

        }
    });    
}
Run Code Online (Sandbox Code Playgroud)

就这样。将其粘贴到任何视图控制器中,在模拟器中运行该应用程序正好 4 分 15 秒,它就会崩溃。

这种崩溃是我以前从未见过的。是“EXC_???(11)”。奇怪的是,您可以在崩溃后按“继续”按钮,它会像平常一样继续。

为什么会崩溃?如何将长任务提交到队列而不导致此行为?

到目前为止,我尝试过以下一些方法,但还没有解开这个谜团:

  • 创建我自己的调度队列(包括后台线程上的调度队列)
  • 使用 NSBlockOperation 而不是 GCD (仍然崩溃)
  • 插入睡眠。短暂的睡眠(少于 5 秒左右)似乎会延迟睡眠时间的崩溃。睡眠时间越长似乎作用越多。所以如果你睡眠一次五秒,它会在 4m 20s 而不是 4m 15s 时崩溃。如果你睡眠一次持续 60 秒,大约需要十分钟才会崩溃,但它最终会发生。这条线索似乎很重要,但我不知道它意味着什么。

更新#1

该问题仅在 LLDB 下重现,在 …

objective-c nsoperationqueue grand-central-dispatch ios

1
推荐指数
1
解决办法
1121
查看次数

如果在串行 DispatchQueue 中触发上下文切换会发生什么?

原则上,串行DispatchQueue会一个接一个地执行提交的任务。但是,如果在一项任务中触发了上下文切换(例如,调用sleep)怎么办?队列是立即执行下一个任务,还是等待当前任务完成?

对于此代码:

q.async {
    print("IN 1")
    var i = 1
    while i < 10 {
     Thread.sleep(forTimeInterval: 0.1)
     i += 1
    }
    print("OUT of 1")
}

q.async {
    print("IN 2")
}
Run Code Online (Sandbox Code Playgroud)

结果是:

// IN 1 -> OUT of 1 -> IN 2 ?
// or IN 1 -> IN 2 -> OUT of 1 ?
Run Code Online (Sandbox Code Playgroud)

我尝试在操场上运行代码,但似乎sleep(和Thread.sleep)在操场中不起作用。

multithreading grand-central-dispatch swift swift-playground

1
推荐指数
1
解决办法
167
查看次数

将三个动画间隔一秒钟的最佳方法是什么?

有没有比使用asyncAfter3 次更好的方法将这些动画间隔一秒?

let firstAnimationTime = DispatchTime.now()
let secondAnimationTime = DispatchTime.now() + 1
let thirdAnimationTime = DispatchTime.now() + 2
DispatchQueue.main.asyncAfter(deadline: firstAnimationTime) {
    self.firstAnimation()
}
DispatchQueue.main.asyncAfter(deadline: secondAnimationTime) {
    self.secondAnimation()
}
DispatchQueue.main.asyncAfter(deadline: thirdAnimationTime) {
    self.thirdAnimation()
}
Run Code Online (Sandbox Code Playgroud)

grand-central-dispatch ios swift

1
推荐指数
1
解决办法
187
查看次数

dispatch_get_main_queue 在第二次调用的方法中崩溃

我有一个 ViewController,它在 AddressBook 中获取数据。为了在获取数据时收到通知,我向此 ViewController 发布通知以允许它更新 NSViewTable(在主队列中)。当用户结束在 ViewController 视图中编辑 NSTextField 时,此 ViewController 会显示一个瞬态 NSPopover .

当我在此字段中输入第一个字符串时,弹出窗口将显示,然后在用户完成与其交互时关闭。如果我再次编辑文本字段,Popover 不会出现在视图中,但提取过程开始。当它结束并且DataUpdated专门用于通知帖子的方法被触发时。然后我dispatch_sync(dispatch_get_main_queue(), ^{在线路上崩溃了(控制台中没有消息,即使启用了 NSZombie)。这是弹出内容 ViewController 中的代码:

- (void) getContactForName: (NSString *) name
{

    CNEntityType entityType = CNEntityTypeContacts;
    if ([CNContactStore authorizationStatusForEntityType:entityType]){
        CNContactStore *store = [[CNContactStore alloc] init];
        [store requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _nullableError){
            if (granted) {
                if ([CNContactStore class]){
                    NSError *contactError;
                    CNContactStore *addressBook = [[CNContactStore alloc] init];
                    [addressBook containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers:@[addressBook.defaultContainerIdentifier]] error:&contactError];
                    NSArray * keysToFetch =@[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactFamilyNameKey, CNContactGivenNameKey, CNContactIdentifierKey];
                    NSError *error; …
Run Code Online (Sandbox Code Playgroud)

macos grand-central-dispatch cncontactstore

1
推荐指数
1
解决办法
621
查看次数

DispatchQueue 绑定到确切的线程

我正在开发一个应用程序,它使用一些框架通过 openGL 绘制 3D 人员。这个框架要求我draw() 从完全相同的线程调用方法。

所以我创建了一个串行 DispatchQueue 并在其中启动 CADisplayLink,draw()以 60FPS调用。我必须从这个确切的线程调用其他一些方法,例如start()stop()。这使队列对我来说是完美的解决方案。

您可能知道 DispathQueue 不保证在同一线程上执行每个任务。这对我来说压力很大,因为它可能会破坏我的应用程序。

我真的不喜欢创建 NSThread 并在其上实现我自己的队列的想法。

有没有办法将 DispatchQueue 绑定到精确的线程?也许可以绑定 NSOperationQueue ?

multithreading grand-central-dispatch ios

1
推荐指数
1
解决办法
1164
查看次数

为什么 concurrentQueue.sync 不会导致死锁

这段代码会死锁,因为:

  1. 他们在同一个线程中
  2. 打印(2)必须等待打印(3)
  3. 打印(3)必须等待打印(2)

例如:

DispatchQueue.main.async {
    print(Thread.current)
    DispatchQueue.main.sync {
        print(Thread.current)
        print(2)
    }
    print(3)
}
Run Code Online (Sandbox Code Playgroud)

为什么在concurrentQueue不会造成死锁?他们也在同一个线程中。

DispatchQueue.global().async {
    print(Thread.current)
    DispatchQueue.global().sync {
        print(Thread.current)
        print(2)
    }
    print(3)
}
Run Code Online (Sandbox Code Playgroud)

concurrency deadlock grand-central-dispatch ios

1
推荐指数
1
解决办法
642
查看次数

主线程上的异步任务和同步任务一样吗?

我知道这两种之间的区别。

对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,任务将被分派到多个线程。
对于同步任务,下一个任务将在当前任务完成后运行。

主线程如何运行异步任务,因为它只有一个线程?

这让我很困惑。
提前致谢。

grand-central-dispatch ios swift

1
推荐指数
1
解决办法
268
查看次数

Swift GCD:为什么信号处理程序在函数中不起作用

使用这个答案作为参考,我试图在我的 swift linux 脚本中实现一个信号处理程序,它将使程序保持活动状态直到 Ctrl-C,然后在收到 SIGINT 时运行一些清理。使用该答案中的代码在主函数中效果很好:

import Dispatch
import Foundation

signal(SIGINT, SIG_IGN) // // Make sure the signal does not terminate the application.

let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
    print("Got SIGINT")
    // ...
    exit(0)
}
sigintSrc.resume()
dispatchMain()
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试将信号处理程序移动到一个函数中,如下所示:

public func registerSigint() {
    signal(SIGINT, SIG_IGN)
    let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
    sigintSrc.setEventHandler {
        print("Got SIGINT")
        exit(0)
    }
    sigintSrc.resume()
}
Run Code Online (Sandbox Code Playgroud)

...

registerSigint()
dispatchMain()
Run Code Online (Sandbox Code Playgroud)

程序在 CTRL-C SIGINT 上无限期挂起。为什么这表现不同?

sigint grand-central-dispatch swift

1
推荐指数
1
解决办法
156
查看次数

GCD中的弱Self,访问self的TableView属性

我看到很多这样的代码:

DispatchQueue.main.async {
    self.tableView.reloadData()
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下, wheretableView是 的属性self,应该确保weak self像这样捕获:

DispatchQueue.main.async { [weak self] in
    self?.tableView.reloadData()
}
Run Code Online (Sandbox Code Playgroud)

我认为是这样,但是这种类型的“不安全”代码在代码库中无处不在,我想知道我是否遗漏了什么?

closures grand-central-dispatch swift

1
推荐指数
1
解决办法
157
查看次数

DispatchQueue 的行为不像串行队列

通过使用以下代码,我期望每次调用 func 时,执行之间的最短时间为 3-4 秒。

但是:当我writeData()连续调用4 次时,我看到异步块在不等待前一次调用完成的情况下执行。

func writeData(){
    DispatchQueue(label: "be.io").asyncAfter(deadline: .now() + 1) {
        print("START :\(Int64((Date().timeIntervalSince1970 * 1000.0).rounded()))")
        Thread.sleep(forTimeInterval: 3)
    }
}
...
writeData()
writeData()
writeData()
writeData()
Run Code Online (Sandbox Code Playgroud)

预期的输出应该是这样的:

START :1611250630000
START :1611250634000
START :1611250638000
START :1611250642000
Run Code Online (Sandbox Code Playgroud)

但在执行时,我得到了所有 4 个调用相同的时间戳(大约 1 毫秒的差异)。

START :1611250630000
START :1611250630000
START :1611250630000
START :1611250630000
Run Code Online (Sandbox Code Playgroud)

我在做什么错?

PS我毫不拖延地尝试了异步,没有运气。

grand-central-dispatch ios swift dispatch-queue

1
推荐指数
1
解决办法
54
查看次数