Есть ли способ приостановить NSTHread на неопределенный срок и возобновить его из другого потока?

Кажется, что это единственные способы уложить NSThread в сон

* sleepForTimeInterval:

* sleepUntilDate:

Будет ли плохой практикой то, что я спрашиваю?

3 ответа

Решение

Вы хотите, чтобы ваш поток просто остановился, пока какой-нибудь другой поток не скажет, что он снова запустится? Если это так, вы можете использовать NSConditionLock. NSConditionLock похож на условную переменную. У него есть пара основных методов, lockWhenCondition и unlockWithCondition, и lock. Типичное использование состоит в том, чтобы ваш фоновый поток ожидал блокировки условия с помощью "lockWhenCondition:", а внутренний поток - для установки условия, которое вызывает пробуждение фонового потока. Условие представляет собой простое целое число, обычно перечисление.

Вот пример:

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];
}

В этом примере, когда startDoingWork называется doBackgroundWork: запускается в фоновом потоке, но затем останавливается, потому что нет никакой работы. После вызова notifyBackgroundThreadAboutNewWork doBackgroundWork: запустит и обработает новую работу, а затем вернется в спящий режим в ожидании доступности новой работы, что произойдет при следующем вызове notifyBackgroundThreadAboutNewWork.

Если у вас действительно есть задачи, которые нужно выполнить в фоновом потоке, но для выполнения одной задачи необходимо выполнить другую, прежде чем она будет выполнена, я бы порекомендовал взглянуть на NSOperation и NSOperationQueue. NSOperation поддерживает установку очень сложных зависимостей, а NSOperationQueue будет обрабатывать планирование и выполнение этих операций в любом подходящем фоновом потоке в правильном порядке. Документация Apple на них довольно хорошая, и у Дрю МакКормака есть хорошая статья на эту тему в MacResearch.

Непонятно, что ты хочешь делать. Остановить поток и возобновить ту же функцию в новом потоке? (Это было бы бессмысленно - что случилось со старым потоком?) Остановить поток и возобновить ту же функцию в другом существующем потоке?

В любом случае, нет, это невозможно, и это даже не хорошая идея. Правильное решение - разделить вашу функцию на две части, а затем использовать часть или весь цикл выполнения, NSTimer, performSelector… методы и NSPort для достижения того, что вы хотите сделать.

Ваша программа будет работать намного лучше, без всякой магии темных нитей, которую вы себе представляете.

Другие вопросы по тегам