原文地址:http://shaheengandhi.com/controlling-thread-exit/
这是讲iOS的线程的文章,下面的内容,自己都惨不忍睹啊,哈哈,练习翻译一下文章,英语太差啊,尽量止步吧。。。。
--------------------------------分割线--------------------------------------------------------------------
CocoaAsyncSocket
库,这个库在iOS上很好的抽象和封装了复杂的socket编程。但是,本文存在意义,就是假设某个工作需要一个单独的线程(不使用GCD),而且我们可以清楚地开始和停止这个线程。所谓清楚的开始和停止这个线程,指的就是当我们决定要开始或者停止这线程时,我们必须保证这个线程做了初始化或者销毁工作。
NSAutoreleasePool
和 an
NSRunLoop
也需要被被创建线程的那段代码管理。这里有一个代码片段,是关于设置自动释放池(
autorelease pool)和启动运行时循环(NSRunLoop)的。
- (void)start
{
if (_thread) {
return;
}
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadProc:) object:nil];
}
- (void)threadProc:(id)ignored
{
@autoreleasepool {
// Startup code here
// Just spin in a tight loop running the runloop.
do {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]
} while (TRUE);
}
}
performSelector:
,
你需要给运行时循环添加一个你自己的输入源,让线程进入休眠状态。使用输入源给线程发送任务是非常有效地,但这个练习就留给读者了。
static void DoNothingRunLoopCallback(void *info)
{
}
- (void)threadProc:(id)ignored
{
@autoreleasepool {
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} while (TRUE);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
}
}
kCFRunLoopRunStopped
说明runloop可以被这个方法停止
CFRunLoopStop
。
这也是
CFRunLoopRun
可以退出的原因(除了没有输入源和定时器,但这种情况不会出现,因为我们有假的输入源),我们也不需要为
CFRunLoopRunInMode
操心,也不需要检查条件。
CFRunLoopStop
。我们可以这样使用:
performSelector:onThread:withObject:waitUntilDone:
.
- (void)threadProc:(id)ignored
{
@autoreleasepool {
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
// Keep processing events until the runloop is stopped.
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
}
}
我们可以像下面的代码一样在任何其他线程里退出这目标线程,包括目标线程它自己。
- (void)stop
{
[self performSelector:@selector(_stop) onThread:_thread withObject:nil waitUntilDone:NO];
_thread = nil;
}
- (void)_stop
{
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)start
{
if (_thread) {
return;
}
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadProc:) object:nil];
// _condition was created in -init
[_condition lock];
[_thread start];
[_condition wait];
[_condition unlock];
}
- (void)stop
{
if (!_thread) {
return;
}
[_condition lock];
[self performSelector:@selector(_stop) onThread:_thread withObject:nil waitUntilDone:NO];
[_condition wait];
[_condition unlock];
_thread = nil;
}
- (void)threadProc:(id)object
{
@autoreleasepool {
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
[_condition lock];
[_condition signal];
[_condition unlock];
// Keep processing events until the runloop is stopped.
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
[_condition lock];
[_condition signal];
[_condition unlock];
}
}
NSCondition
makes no promise that it is free from using -autorelease
in its implementations of -lock
, -signal
, and-unlock
. 那就意味着应该有一个有效的NSAutoreleasePool,当使用这些API的时候。我们有两个解决方案。我们可以手动执行自动释放池,或者使用另一种同步方式来同步线程的退出。第一种方式有点杂乱。第二种方式有太多的变量。
NSAutoreleasePool,你必须关闭ARC。
-[NSAutoreleasePool release]一样有效,当我们释放后自动释放池就不再有效了。所以,手动释放释放池就意味着新建另一个自动释放池来保证NSCondition的API有正确的环境。
- (void)threadProc:(id)object
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
[_condition lock];
[_condition signal];
[_condition unlock];
// Keep processing events until the runloop is stopped.
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
// Release all accumulated resources, but make sure NSCondition has the
// right environment.
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
[_condition lock];
[_condition signal];
[_condition unlock];
}
[pool drain];
}
使用
NSThreadWillExitNotification
- (void)stop
{
if (!_thread) {
return;
}
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@(_signal) name:NSThreadWillExitNotification object:_thread];
[_condition lock];
[self performSelector:@selector(_stop) onThread:_thread withObject:nil waitUntilDone:NO];
[_condition wait];
[_condition unlock];
[nc removeObserver:self name:NSThreadWillExitNotification object:_thread];
_thread = nil;
}
- (void)threadProc:(id)object
{
@autoreleasepool {
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
[_condition lock];
[_condition signal];
[_condition unlock];
// Keep processing events until the runloop is stopped.
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
}
}
- (void)_signal
{
[_condition lock];
[_condition signal];
[_condition unlock];
}
NSCondition
仍然可以用作启动的同步方案。因为它没被用作其他用处,不是必须加锁在线程启动之前。但是为了与之前的代码保持一致性,我们会遵循之前的模式,当新建一个线程的时候,让他保持挂起状态,当它获得了条件锁的时候在恢复执行状态。
static void *ThreadProc(void *arg)
{
ThreadedComponent *component = (__bridge_transfer ThreadedComponent *)arg;
[component threadProc:nil];
return 0;
}
- (void)start
{
if (_thread) {
return;
}
if (pthread_create_suspended_np(&_pthread, NULL, &ThreadProc, (__bridge_retained void *)self) != 0) {
return;
}
// _condition was created in -init
[_condition lock];
mach_port_t mach_thread = pthread_mach_thread_np(_pthread);
thread_resume(mach_thread);
[_condition wait];
[_condition unlock];
}
- (void)stop
{
if (!_thread) {
return;
}
[self performSelector:@selector(_stop) onThread:_thread withObject:nil waitUntilDone:NO];
pthread_join(_pthread, NULL);
_thread = nil;
}
- (void)threadProc:(id)object
{
@autoreleasepool {
CFRunLoopSourceContext context = {0};
context.perform = DoNothingRunLoopCallback;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
// Obtain the current NSThread before signaling startup is complete.
_thread = [NSThread currentThread];
[_condition lock];
[_condition signal];
[_condition unlock];
// Keep processing events until the runloop is stopped.
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
}
}