iOS: обработка кода OpenGL, выполняющегося в фоновых потоках во время перехода приложения
Я работаю над приложением для iOS, которое, скажем одним нажатием кнопки, запускает несколько потоков, каждый из которых выполняет фрагмент кода Open GL. Эти потоки либо имеют другой набор EAGLContext, либо, если они используют один и тот же EAGLContext, то они синхронизируются (то есть 2 потока не устанавливают один и тот же EAGLContext параллельно).
Теперь предположим, что приложение переходит в фоновый режим. Согласно документации Apple, мы должны прекратить все вызовы OpenGL в applicationWillResignActive:
обратный звонок, так что к тому времени applicationDidEnterBackground:
вызывается, дальнейшие вызовы GL не выполняются.
я использую dispatch_queues
создавать фоновые темы. Например:
__block Byte* renderedData; // some memory already allocated
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
glViewPort(...)
glBindFramebuffer(...)
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
}
use renderedData for something else
Мой вопрос - как справиться applicationWillResignActive:
так что любые такие фоновые вызовы GL могут быть не просто остановлены, но и иметь возможность возобновить applicationDidBecomeActive:
? Должен ли я дождаться завершения текущих блоков, прежде чем вернуться из applicationWillResignActive:
? Или я должен просто приостановить glProcessingQueue
и вернуться?
Я также читал, что подобное имеет место в случае, когда приложение прерывается другими способами, такими как отображение предупреждения, телефонный звонок и т. Д.
У меня может быть несколько таких потоков в любой момент времени, вызванных, возможно, несколькими ViewControllers, поэтому я ищу какое-то масштабируемое решение или шаблон проектирования.
1 ответ
Как я вижу, вам нужно либо приостановить поток, либо убить его.
Если вы убьете его, вам нужно убедиться, что все ресурсы освобождены, что означает повторный вызов openGL, скорее всего. В этом случае может быть лучше просто дождаться окончания выполнения блока. Это означает, что блок не должен занимать слишком много времени для завершения, что невозможно гарантировать, и, поскольку у вас несколько контекстов и потоков, это может реально представлять проблему.
Так что пауза кажется лучше. Я не уверен, есть ли прямой API для приостановки потока, но вы можете заставить его ждать. Может быть, как система, похожая на эту, может помочь.
Связанный пример, кажется, обрабатывает именно то, что вы хотели бы; он уже проверяет текущий поток и блокирует его. Я думаю, вы могли бы упаковать это в какой-то инструмент в виде статического метода или функции C, и где бы вы ни были уверены, вы можете приостановить поток, вы просто сделаете что-то вроде:
dispatch_sync(glProcessingQueue, ^{
[EAGLContext setCurrentContext:_eaglContext];
[ThreadManager pauseCurrentThreadIfNeeded];
glViewPort(...)
glBindFramebuffer(...)
[ThreadManager pauseCurrentThreadIfNeeded];
glClear(...)
glDrawArrays(...)
glReadPixels(...) // read in renderedData
[ThreadManager pauseCurrentThreadIfNeeded];
}
У вас все еще может быть проблема с основным потоком, если он используется. Возможно, вы захотите пропустить паузу на этом, иначе ваша система может просто больше никогда не проснуться (хотя не уверен, попробуйте).
Итак, теперь вы посмотрите на интерфейс вашего ThreadManager
быть чем-то вроде:
+ (void)pause {
__threadsPaused = YES;
}
+ (void)resume {
__threadsPaused = NO;
}
+ (void)pauseCurrentThreadIfNeeded {
if(__threadsPaused) {
// TODO: insert code for locking until __threadsPaused becomes false
}
}
Дайте нам знать, что вы узнаете.