im 开发一个应用程序,它使用一些框架通过 openGL 绘制 3D 工作人员。这个框架要求我从完全相同的线程调用draw()
方法。
因此,我创建了一个串行DispatchQueue,并在其中启动了CADisplayLink,以60FPS的速度调用draw()
。我必须从这个确切的线程调用的其他方法很少,例如start()
和stop()
.这使队列成为我的完美解决方案。
如您所知,DispathQueue 不能保证在同一线程上执行每个任务。这对我来说压力很大,因为它可能会破坏我的应用程序。
我真的不喜欢创建 NSThread 并在其上实现我自己的队列的想法。
有没有办法将调度队列绑定到确切的线程?也许NSOperationQueue可以绑定?
正如 Apple 文档所说:
在向应用程序添加并发性时,调度队列比线程具有多个优势。最直接的优点是工作队列编程模型的简单性。对于线程,您必须为要执行的工作以及线程本身的创建和管理编写代码。调度队列可让您专注于实际想要执行的工作,而不必担心线程的创建和管理。相反,系统会为您处理所有线程的创建和管理。优点是系统能够比任何单个应用程序更有效地管理线程。系统可以根据可用资源和当前系统条件动态扩展线程数。此外,与自己创建线程相比,系统通常能够更快地开始运行任务。
简而言之,您要么使用调度队列,简单地创建它们并将工作发送给它们,要么使用NSThread
和NSRunLoop
,创建它们,设置它们,向它们发送工作,并可能停止它们。
详细地:
NSThread/NSRunLoop
创造:
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMainRoutine) object:nil];
[self.thread start];
启动/管理:
- (void)threadMainRoutine
{
// Set the runLoop variable, to signal this thread is alive
self.runLoop = [NSRunLoop currentRunLoop];
// Add a fake Mach port to the Run Loop, to avoid useless iterations of the main loop when the
// thread is just started (at this time there are no events added to the run loop, so it will
// exit immediately from its run() method)
[self.runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
//--- Thread main loop
while (thread_KeepRunning)
{
// Run the run loop. This function returns immediately if the RunLoop has nothing to do.
// NOTE: THIS STATEMENT:
// [self.runLoop run];
// DOES NOT WORK, although it is equivalent to CFRunLoopRun();
CFRunLoopRun();
}
// Unset the runLoop variable, to signal this thread is about to exit
self.runLoop = nil;
}
添加要对其执行的工作:
[self performSelector:@selector(mySelector:) onThread:myThread withObject:myObject waitUntilDone:YES];
关闭:
- (void)stop
{
if (self.thread) {
while (self.thread.isExecuting) {
thread_KeepRunning = NO;
CFRunLoopStop([self.runLoop getCFRunLoop]);
[NSThread sleepForTimeInterval:0.1f];
}
}
self.runLoop = nil;
self.thread = nil;
}
调度队列
创造:
dispatch_queue_t myQueue = dispatch_queue_create("My Queue", DISPATCH_QUEUE_SERIAL);
开始:
dispatch_resume(myQueue);
添加要对其执行的工作:
dispatch_async(myQueue, (void)^ {
// put the work into this block
});
关闭:
dispatch_suspend(myQueue);
myQueue = nil;
此外,苹果文档说
由于 Grand Central Dispatch 管理您提供的任务与运行这些任务的线程之间的关系,因此通常应避免从任务代码调用 POSIX 线程例程。如果出于某种原因确实需要调用它们,则应非常小心调用哪些例程
所以:如果你使用调度队列,不要弄乱线程。