代码之家  ›  专栏  ›  技术社区  ›  Michael Waterfall

当等待nsOperationQueue操作取消时,主线程无限期挂起[仅在设备上!]

  •  3
  • Michael Waterfall  · 技术社区  · 16 年前

    我的主线程上有一个nsOperationQueue,它运行一组nsOperation(max concurrent设置为1),我希望可以随时取消这些操作。当我按下一个按钮时,我告诉队列取消所有操作,并等待完成。这应该挂起主线程,直到操作队列为空,但是它将无限期挂起我的主线程。

    以下是我用来阻止它的代码:

    ...
    [myQueue cancelAllOperations];
    [myQueue waitUntilAllOperationsAreFinished];
    return YES; // This line never gets called
    

    注: 我需要使用 waitUntilAllOperationsAreFinished 因为进一步的进程要求队列为空。

    奇怪的是,这只发生在设备上。在模拟器中运行时,它按预期工作。

    我已经观察了断点,并且可以跟踪当前正在运行的操作,直到它完成。它检测到[自我取消],停止它正在做的事情,然后快速移动到 main 方法。我可以看到操作中的任何内容都不会导致挂起,并且通过取消所有操作,其他操作都不会启动,队列也会结束。我通过添加断点进行了检查,其他操作都没有启动。

    为什么会这样?

    3 回复  |  直到 16 年前
        1
  •  8
  •   Brad Larson    16 年前

    在任何操作中(或在任何其他线程中),是否使用 -performSelectorOnMainThread:withObject:waitUntilDone: ? -waitUntilAllOperationsAreFinished 将阻塞它调用的任何线程,直到所有操作完成。如果您在应用程序终止时调用它,那么很可能该线程就是主线程。如果主线程被阻塞,并且其中一个操作使用 -performselectornmainthread:withobject:waituntildone: ,您的应用程序将冻结,因为操作永远不会完成。

    我以前也经历过这样的事情。不幸的是,这是相当困难的工作。

        2
  •  5
  •   Kendall Helmstetter Gelner    16 年前

    你永远不应该阻塞主线。它为一件事处理所有的UI更新,为另一件事处理所有的UI更新,正如您注意到的那样,您设法创建了一个死锁。

    相反,尝试创建如下方法:

    - (void) notifyOnFinish
    {
       [myQueue waitUntilAllOperationsAreFinished];
       [self performSelectorOnMainThread:(queueEmpty) withObject:nil waitUntilDone:NO];
    }
    

    然后,如果您现在有代码,请致电:

    [myQueue cancelAllOperations];
    [self performSelectorInBackground:@selector(notifyOnFinish) withObject:nil];
    

    在queueEmpty方法中,当队列清空时,您只需做您想做的任何事情。

    基本上,只需创建一个要阻塞的后台线程,而不是主线程。

        3
  •  0
  •   Jasarien    16 年前

    也许 waitUntilAllOperationsArefFinished 正在造成阻塞…可能所有操作都取消并在呼叫前完成 有效的等待时间 然后队列被挂起,等待已经完成的操作完成…?

    我不知道这是事实,但也许不要打电话 有效的等待时间 .