我曾经认为自己是一个相当聪明的人 苹果的“线程编程指南”,打破了我自我欺骗的自我。
我有一个方法我想在辅助线程上重复运行,在下面的示例中我称之为doStuff:
我希望能够反复停止并开始重复调用此方法。
代码启动线程
如果布尔值stuffToDo为真,则
然后它调用doStuff:
否则
它有一点休息
然后它再次循环,直到我告诉它停止
我目前的代码似乎很浪费,因为即使没有任何事情可以检查'stuffToDo'。
我可以摆脱stuffToDo,只是产生并根据需要取消线程。
这看起来也很浪费,这意味着当我已经运行一个新线程时,我需要注意不要意外产生一个新线程。
我确信在Apple的“线程编程指南”的“运行循环管理”部分可以找到有效解决我的困境的答案。 也许它涉及自定义输入源
但我真的觉得这个文件具有挑战性 就好像这个文档在我的大脑中产生了太多的线程而且计算停止了。
enum eRenderThreadMode
{
render_not_started,
render_run,
render_cancel,
render_finished
};
- (IBAction) startThread:(id)sender
{
self.renderThreadMode = render_run;
label.text = @"doing stuff";
[NSThread detachNewThreadSelector:@selector(keepDoingStuff) toTarget:self withObject:nil];
}
- (void)keepDoingStuff
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
while (renderThreadMode == render_run)
{
if(stuffToDo)
{
[self doStuff];
}
else
{
[NSThread sleepForTimeInterval:kLittleRest];
}
}
self.renderThreadMode = render_finished;
[pool release];
}
- (IBAction)stopThread:(id)sender
{
self.renderThreadMode = render_stop;
while (self.renderThreadMode == render_cancel)
{
[NSThread sleepForTimeInterval:kLittleRest];
}
}
答案 0 :(得分:7)
您可以使用辅助线程休眠的同步对象。 This Apple page表示有一个名为条件的工具可能会做你想要的。使用Condition或类似的同步对象只会在需要完成工作时(或者当线程死亡的时候)唤醒你的线程。
答案 1 :(得分:7)
是的,你是正确的,你想使用runloop,你缺少的是如何设置这一切。我将修改你的帖子并解释发生了什么。不要担心,如果它吓唬你,它是棘手的,有一些你只从经验中学到的陷阱
- (IBAction) startThread:(id)sender
{
self.renderThreadMode = render_run;
label.text = @"doing stuff";
self.backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(keepDoingStuff) object:nil];
[self.backgroundThread start];
}
//Okay, this is where we start changing stuff
- (void)keepDoingStuff
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//A runloop with no sources returns immediately from runMode:beforeDate:
//That will wake up the loop and chew CPU. Add a dummy source to prevent
//it.
NSRunLoop *runLopp = [NSRunLoop currentRunLoop];
NSMachPort *dummyPort = [[NSMachPort alloc] init];
[runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode];
[dummyPort release];
[pool release];
while (1)
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[loopPool drain];
}
}
好的,所以在这一点上你应该看看上面的代码并思考“嗯,这可能是一个很好的睡眠线程,但它没有做任何事情。这是事实,但因为它有一个活跃的runloop我们可以做任何基于runloop的事情,包括performSelector:onThread:withObject:waitUntilDone:
- (void) doStuffOnBackgroundThread
{
[self performSelector:@selector(doStff) onThread:self.backgroundThread withObject:nil waitUntilDone:NO];
}
当您在主线程(或任何其他线程)上调用上述方法时,它将编组各种参数并将指定线程的runloop入队,并在必要时将其唤醒。在这种情况下,将导致self.backgroundThread从runMode唤醒:beforeDate:,执行-doStuff,然后循环返回aroound循环并返回睡眠等待runMode:beforeDate:。如果你想能够拆除线程,你可以像在代码中一样在while循环中设置一个变量,但是要记住线程会在睡眠时消失,除非你把它唤醒,所以最好封装一下在一个通过performSelector设置控制变量的方法中:onThread:withObject:waitUntilDone:,作为一个加号,意味着该变量只能从后台线程设置,这简化了同步问题。
好吧,所以我认为这可以解决你的问题,所以有时间制作强制性的插件:你确定要用线程做这个吗? NSOperation和NSOperationQueue可能是一个更简单的解决方案,可以解决所有线程问题,如果您需要做的只是偶尔将某些数据排入队列中。他们将安排工作,管理依赖关系,建立/拆除线程以及处理所有runloop唤醒/睡眠的东西。