Mam obiekt NSRunLoop, do którego załączam timery i strumienie. Działa świetnie. Powstrzymanie to zupełnie inna historia.CFRunLoopRun() vs [NSRunLoop run]
Uruchomię pętlę, używając [runLoop run]
.
Jeśli spróbuję zatrzymać pętlę za pomocą CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop])
, pętla się nie zatrzyma. Jeśli zamiast tego uruchomię pętlę, używając CRunLoopRun()
, to działa. Upewniłem się również, że wywołanie odbywa się na poprawnym wątku (tym, który uruchamia moją niestandardową pętlę uruchamiania). Mam debugowane to z pthread_self()
.
Znalazłem archiwum listy adresowej, w którym programista powiedział: "nie przejmuj się używaniem CRunLoopStop()
, jeśli uruchomiłeś pętlę, korzystając z metody uruchamiania NSRunLoop
". Mogę zrozumieć, dlaczego tak właśnie jest - zazwyczaj parujesz inicjalizatory i finalizatory z tego samego zestawu funkcji.
Jak zatrzymać NSRunLoop
bez "uciekania się do CF"? Nie widzę metody stop
na NSRunLoop
. Docs mówi, że można zatrzymać pętlę run na trzy sposoby:
- Skonfiguruj pętli run uruchomić o wartości limitu czasu
- Powiedz pętlę run przestać używać
CFRunLoopStop()
- Usuń wszystkie źródła wejściowe, ale to niewiarygodny sposób na zatrzymanie pętli, ponieważ nigdy nie wiadomo, co utknęło w pętli za plecami.
Cóż, już próbowałem 2. i jest to "brzydkie" uczucie, ponieważ musieć kopać do CF. 3. nie wchodzi w rachubę - nie podoba mi się niedeterministyczny kod.
To daje nam 1. Jeśli rozumiem dokumenty poprawnie, nie można "dodać" limitu czasu do już istniejącej pętli uruchamiania. Możesz uruchamiać tylko nowe pętle uruchamiania z limitem czasu. Jeśli uruchomię nową pętlę uruchamiania, nie rozwiąże ona mojego problemu, ponieważ utworzy ona zagnieżdżoną pętlę uruchamiania. Wciąż wskakuję z powrotem do starego, tego samego chciałem zatrzymać ... prawda? Mogłem źle to zrozumieć. Ponadto nie chcę uruchamiać pętli z wartością limitu czasu. Jeśli to zrobię, będę musiał dokonać kompromisu pomiędzy spalaniem cykli procesora (mała wartość limitu czasu) a czasem reakcji (wysoka wartość limitu czasu).
Jest to konfiguracja mam teraz (pseudo kod-owski):
Communicator.h
@interface Communicator : NSObject {
NSThread* commThread;
}
-(void) start;
-(void) stop;
@end
Communicator.m
@interface Communicator (private)
-(void) threadLoop:(id) argument;
-(void) stopThread;
@end
@implementation Communicator
-(void) start {
thread = [[NSThread alloc] initWithTarget:self
selector:@selector(threadLoop:)
object:nil];
[thread start];
}
-(void) stop {
[self performSelector:@selector(stopThread)
onThread:thread
withObject:self
waitUntilDone:NO];
// Code ommitted for waiting for the thread to exit...
[thread release];
thread = nil;
}
@end
@implementation Communicator (private)
-(void) stopThread {
CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]);
}
-(void) threadLoop:(id) argument {
// Code ommitted for setting up auto release pool
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
// Code omitted for adding input sources to the run loop
CFRunLoopRun();
// [runLoop run]; <- not stoppable with
// Code omitted for draining auto release pools
// Code omitted for signalling that the thread has exited
}
@endif
Czym jestem do zrobienia? Czy jest to powszechne/dobry wzór, aby poradzić sobie z CF? Nie znam wystarczająco dobrze Fundacji. Czy ingerencja w warstwę CF jest potencjalnie niebezpieczna (w odniesieniu do uszkodzenia pamięci, niespójności, wycieków pamięci)? Czy istnieje lepszy wzór do osiągnięcia tego, co próbuję osiągnąć?
Ah, sprytnie! Nie widziałem, aby 'runMode' działał tylko raz. Czy występuje znaczna kara za wydajność spowodowana ponownym uruchomieniem pętli? –
Nie, nie ma: tak działają '- [Uruchom NSRunLoop]' i '- [NSRunLoop runUntilDate:]'. –
Wątek nie zatrzyma się, jeśli ustawisz runLoopIsStopped na YES. Musisz ustawić to na TAK i wykonać akcję na tym wątku programu runloop, w przeciwnym razie [runLoop runMode: NSDefaultRunLoopMode beforeDate: date] nie zostanie zakończony. To zajęło mi wieki, aby dowiedzieć się. – Pada