【问题标题】:Thread is being killed by the OS线程被操作系统杀死
【发布时间】:2011-11-07 21:20:14
【问题描述】:

我目前正在编写一个从影片剪辑中提取帧的应用程序。我设计它以便提取将在单独的线程上完成,以防止应用程序冻结。提取过程本身会占用大量资源,但在模拟器中使用时效果很好。但是,在为 iPad 构建它时存在问题。当我执行另一个操作时(我告诉我的 AV 播放器在我提取帧时播放),线程意外停止工作,我相信它被杀死了。

我认为这是因为我使用了大量资源,但并不完全确定。

这是我的问题: 1. 如何判断我的线程是否/为什么停止? 2. 如果真的是过度加工怎么办?我真的需要执行此操作。

这是我使用的一些代码: 创建线程:

[NSThread detachNewThreadSelector:@selector(startReading) toTarget:self withObject:nil];

我会发布您需要的任何信息, 非常感谢!

更新 我现在正在使用 GCD,它会为我填充线程。但是操作系统仍然会杀死线程。

我确切地知道它何时发生。当我告诉我的 [AVplayer 播放] 时;它会杀死线程。

这个问题只发生在实际的 iPad 上而不是模拟器上

【问题讨论】:

  • 如果你不得不问,请尝试使用更高级别的抽象,例如调度队列 (GCD) 或操作队列 (NSOperationQueue)。请参阅The Move Away from Threads 进行扩展讨论,或查找GCDNSOperationQueue 示例。这是非常有用的东西。
  • 您的应用程序崩溃了吗?如果是这样,崩溃报告说什么?你确定 AVPlayer 是线程安全的吗?因为如果您正在调用 [AVplayer play] 并在后台线程中同时访问它,那可能就是问题所在。
  • 您的提取线程是否作为后台线程运行?我正在学习 Objective-C,但是,如果您能够将其作为后台线程运行,则有助于避免被操作系统杀死。

标签: iphone ios multithreading ipad


【解决方案1】:

在我看来,您正试图同时解码两个视频剪辑。由于 iPad 基于硬件的解码特性,它一次只能支持一个解码过程。当您播放新项目时,旧项目将被取消。这可以解释为什么它在模拟器中有效,但在设备上无效。

至于解决方案,您可以切换到纯软件解码器,如libav(GPL)或CoreAVC SDK(商业)。这样您就不会干扰硬件解码器的播放。

【讨论】:

    【解决方案2】:

    当某些东西在模拟器上运行而在设备上不起作用时,一个明显的解释肯定是资源限制问题。但有时模拟器也无法准确模拟设备功能的其他方面。所以我想知道这种情况是否还有其他解释。我想到了一种可能性,它可能是对有限资产的竞争——对 AV 资产的访问——这意味着当你开始播放它时,它也不再可供处理(并且由于某种原因模拟器中的错误不显示此限制。)

    AV Foundation Programming Guide, under "Playing Assets"Apple 声明中:

    虽然最终您想要播放资源,但您不会直接将资源提供给 AVPlayer 对象。相反,您提供了一个 AVPlayerItem 的实例。播放器项目管理与其关联的资产的呈现状态。播放器项目包含播放器项目轨道(AVPlayerItemTrack 的实例),它们对应于资产中的轨道。

    这种抽象意味着您可以同时使用不同的播放器播放给定的资产,但每个播放器以不同的方式呈现。例如,使用项目轨道,您可以在播放期间禁用特定轨道(您可能不想播放声音组件)。

    所以我想知道——你是否使用 AVPlayerItems 来访问你的资产,这会让这两个操作同时发生?如果是这样,至少排除了该特定方向。但如果没有,可能值得调查,看看它是否能解决问题。

    可能会抓住稻草。但可能会导致某个地方。

    【讨论】:

    • 现在我知道,当我在使用此资产启动 AVPlayer 后从资产中读取帧时,线程正在停止,但我该如何绕过它?
    • 如果您不通过 AVPlayerItem 访问资产,您应该提供一个 AVPlayerItem 实例来播放资产,并提供第二个 AVPlayerItem 实例来从资产中读取帧。这应该允许两者同时发生。
    • 我正在使用 AVPlayer 资产来播放资产但不读取帧。对于使用 AVAssetReader 的即时消息,它是由资产本身启动的。你会如何建议这样做?
    【解决方案3】:

    在 Apple 的线程编程指南第 27 页的“设置线程的堆栈大小”部分中说:

    在 iOS 和 Mac OS X v10.5 及更高版本中,分配和初始化一个 NSThread 对象(不要使用 detachNewThreadSelector: toTarget: withObject: 方法)

    尽管在第 22 页中说 detachNewThreadSelector 是使用 NSThread 创建线程的方法之一。

    它在第 23 页中给出了如何启动线程的示例:

    NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(myThreadMainMethod:) object:nil];
    [myThread start];
    

    根据将在您的应用中创建分离线程的指南。尝试以这种方式创建你的线程,看看操作系统是否停止杀死你的线程。

    参考这里是指南的链接

    http://developer.apple.com/library/ios/iPad/#documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW2

    它还在第 29 页中提到,如果您的应用程序使用托管内存模型(您似乎就是这样),那么您应该首先在线程入口例程中创建一个自动释放池,并且类似地销毁它是您的线程做的最后一件事.不确定不这样做会导致您的线程被杀死,但请验证您是否这样做。

    在你的线程入口例程中有一个 try/catch 块可能无法解决终止问题,但是如果你的线程中发生错误,它将避免你的应用程序退出。

    我忘了提到另一个可以帮助您解决资源限制的设计技巧,正如 Duncan 所提到的。根据指南第18页:

    避免共享数据结构

    避免线程相关资源的最简单最简单的方法 冲突是给程序中的每个线程自己的副本 它需要的任何数据。当您最小化 线程之间的通信和资源争用。

    我认为你可以在你的应用中做到这一点。除了做 Duncan 提到的“不要直接向 AVPlayer 对象提供资产,而是提供 AVPlayerItem 的实例”之外,还要为每个线程创建单独的实例,一个 AVPlayerItem 实例用于播放器线程,一个 AVPlayerItem 实例用于提取线程。

    【讨论】: