views:

1122

answers:

3

Seems these are the only methods to put a NSThread to sleep

* sleepForTimeInterval:

* sleepUntilDate:

Would it be bad practice what I am asking?

A: 

It's not clear what you want to do. Stop the thread and resume the same function on a new thread? (That would be pointless—what was wrong with the old thread?) Stop the thread and resume the same function on another existing thread?

Either way, no, it's not possible, and it's not even a good idea. The correct solution is to split your function in two, then use some or all of the run loop, NSTimer, the performSelector… methods, and NSPort to achieve whatever it is you want to do.

Your program will work much better without all this dark thread magic going on that you're envisioning.

Peter Hosey
you dontunderstandthatI want to be able to stop the thread whenever i want. So splittin the task would be pointless.
yan bellavance
Why would you want to do that? If you want to stop the work you're doing, do that. Otherwise, you're likely to stop the thread in the middle of something, with that thing half-completed and half-not.
Peter Hosey
Do you realise that instead of helping meyour just arguing. I dont know how you got to 10k
yan bellavance
I got close to 10k by helping people. That's what I tried to do here as well. Seems I didn't succeed; Jon Hess saw what you wanted better than I did.
Peter Hosey
You did ask if it would be bad practice, and he's answering you. He gained his rep points the same way as anyone else: providing answers that people find useful. If you want a clear answer, I suggest asking a clear question to begin with. (For example, explaining why or what you hope to accomplish can potentially lead to better ideas than what may be obvious at first.) I'm glad you found an answer that helps answer your question, but know that most of us are probably as confused as Peter was.
Quinn Taylor
+7  A: 

Do you want your thread to just stop until some other thread tells it to start up again? If so, you could use an NSConditionLock. An NSConditionLock is similar to a condition variable. It has a couple of basic methods, lockWhenCondition, and unlockWithCondition, and lock. A typical usage is to have your background thread waiting on the condition lock with "lockWhenCondition:", and the in you foreground thread to set the condition, which causes the background thread to wake up. The condition is a simple integer, usually an enumeration.

Here's an example:

enum {
    kWorkTodo = 1,
    kNoWorkTodo = 0
}

- (id)init {
    if ((self = [super init])) {
        theConditionLock = [[NSCoditionLock alloc] initWithCondition: kNoWorkTodo];
        workItems = [[NSMutableArray alloc] init];
    }
}

- (void)startDoingWork {
    [NSThread detachNewThreadSelector:@selector(doBackgroundWork) toTarget:self withObject:nil];
}

- (void)doBackgroundWork:(id)arg {
    while (YES) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSArray *items = nil;
        [theConditionLock lockWhenCondition:kWorkTodo]; // Wait until there is work to do
        items = [NSArray arrayWithArray:workItems]
        [workItems removeAllObjects];
        [theConditionLock unlockWithCondition:kNoWorkTodo];
        for(id item in items) {
            // Do some work on item.
        }
        [pool drain];
    }
}

- (void)notifyBackgroundThreadAboutNewWork {
    [theConditionLock lock];
    [workItems addObject:/* some unit of work */];
    [theConditionLock unlockWithCondition:kWorkTodo];
}

In this example, when startDoingWork is called doBackgroundWork: will start on a background thread, but then stop because there isn't any work to do. Once notifyBackgroundThreadAboutNewWork is called, then doBackgroundWork: will fire up and process the new work, and then go back to sleep waiting for new work to be available, which will happen the next time notifyBackgroundThreadAboutNewWork is called.

Jon Hess
Thank you so much for your solution. this seems like what I need.
yan bellavance
So the process of coordinatingt hreads with NSlock, doesithaveaverylowlatency between threads. I tried using the sleep methodsfor NSthreadand is was really slow.
yan bellavance
Could you also tell me why you do work before and after [theConditionLock unlockWithCondition:kNoWorkTodo];also. what is the difference between nslock and nsconditionlock
yan bellavance
It's not exactly work that he's doing while the lock is locked. The `workItems` array is an inbox; the `notifyBackgroundThreadAboutNewWork` method leaves the new items there, and the code between the `lockWithCondition:` and `unlockWithCondition:` messages extracts the items into a new array (`items`). All of the real work happens after `unlockWithCondition:`, and uses that temporary `items` array.
Peter Hosey
He's using the condition lock as a synchronization point, to allow one thread to signal the other thread that it can proceed with whatever it was doing. The `lockWhenCondition` call effectively causes the background thread to sleep "indefinitely" (as you put it) until the condition is specified to have been met by the foreground thread. As far as the difference between NSLock and NSConditionLock, it's really quite obvious if you read the documentation. With an NSLock, everybody locks on the same thing. A condition lock can specify N different conditions, which allows for finer-grained locking.
Quinn Taylor
The difference between NSLock and NSConditionLock is that an NSLock doesn't have a condition. It's either locked or not. An NSConditionLock, on the other hand, is set to one of any number of conditions; you could have multiple threads all using the same lock, each of which waits for a specific condition, so that those threads operate serially—each unlocking with a different condition than it waited for, so that the next thread, the one that's waiting for that condition, always runs next. (Such code would probably bend one's brain, though, and would certainly defeat the purpose of threading.)
Peter Hosey
I do have one improvement to suggest: Use a single NSMutableArray for `items`, instead of creating it every time, and use `setArray:` to replace its contents with those of the inbox array. This will keep a lid on memory usage, especially if this thread runs for a long time.
Peter Hosey
How about I add an autorelease pool instead.
Jon Hess
+1  A: 

If you really do have tasks that you need to execute on a background thread, yet one task needs for another to be completed before it executes, I'd recommend looking at NSOperation and NSOperationQueue. NSOperation supports setting very complex dependencies, and NSOperationQueue will handle the scheduling and execution of those operations on however many background threads are appropriate, in the right order. Apple's documentation on these is pretty good, and Drew McCormack has a nice article about the topic at MacResearch.

Brad Larson