Objective-C运行循环停止并重新启动方法?

com*_*eye 8 iphone multithreading objective-c

我曾经认为我是一个相当聪明的人.
苹果的"线程编程指南",打破了我自我欺骗的自我.

我有一个方法我想在辅助线程上重复运行,在下面的示例中我称之为doStuff:
我希望能够重复停止并重新启动此方法的重复调用.

代码启动线程.
如果布尔值stuffToDo为true,
则调用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];
    }
}
Run Code Online (Sandbox Code Playgroud)

aem*_*aem 7

您可以使用辅助线程休眠的同步对象.这个Apple页面表明有一个名为Conditions的工具可能会做你想要的.使用Condition或类似的同步对象只会在需要完成工作时(或者当线程死亡时)唤醒您的线程.


Lou*_*arg 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];
        }
}
Run Code Online (Sandbox Code Playgroud)

好了,所以在这一点上,你应该看上面的代码和思考"嗯,这可能是一个不错的睡眠线程,但它不会做任何事情.这是事实,但由于它有一个活跃的runloop我们能做到任何基于它的runloop,包括performSelector:onThread:withObject:waitUntilDone:

- (void) doStuffOnBackgroundThread
{
    [self performSelector:@selector(doStff) onThread:self.backgroundThread withObject:nil waitUntilDone:NO];
}
Run Code Online (Sandbox Code Playgroud)

当您在主线程(或任何其他线程)上调用上述方法时,它将编组各种参数并将指定线程的runloop入队,并在必要时将其唤醒.在这种情况下,这将导致self.backgroundThread从runMode唤醒:beforeDate :,执行-doStuff,然后循环回aroound循环,回去睡在runMode等待:beforeDate :. 如果你希望能够推倒线程,你可以设置在while循环就像你在你的代码有一个变量,但请记住线程会消失,如果它是睡觉,除非你唤醒它,所以它可能是最好封装在经由performSelector设置控制变量的方法:onThread:withObject:waitUntilDone :,为正,这将意味着该变量将只从后台线程这简化同步问题设置.

好吧,所以我认为这可以解决你的问题,所以有时间制作强制性的插件:你确定要用线程做这个吗?NSOperation和NSOperationQueue可能是一个更简单的解决方案,可以解决所有线程问题,如果您需要做的只是偶尔将某些数据排入队列中.他们将安排工作,管理依赖关系,建立/拆除线程以及处理所有runloop唤醒/睡眠的东西.