iOS两个线程间嵌套发送同步消息

简介:  先上代码,主要逻辑可看注释。最好是直接下载demo再往下看了。demo下载地址:http://download.csdn.net/detail/hursing/5159144@implementation ViewController #d...

 先上代码,主要逻辑可看注释。最好是直接下载demo再往下看了。demo下载地址:http://download.csdn.net/detail/hursing/5159144

@implementation ViewController 
 
#define kLevelsOfNesting 5 
NSString *const kParameter = @"Parameter"; 
NSString *const kRunLoop = @"RunLoop"; 
 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // 在界面上增加一个button,点击后才触发发送消息的流程 
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    [button setTitle:@"click me" forState:UIControlStateNormal]; 
    [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 
    button.frame = CGRectMake(50, 50, 100, 30); 
    [self.view addSubview:button]; 
    [NSThread mainThread].name = @"Main Thread"; 
    // 创建一个worker线程 
    m_thread = [[NSThread alloc] initWithTarget:self selector:@selector(secondaryThreadMain:) object:nil]; 
    [m_thread start]; 
} 
 
- (void)sendSynchronousMessageToTheOtherThread:(NSMutableDictionary*)info 
{ 
    // 不能存NSRunLoop进去,它非线程安全 
    NSValue *runLoop = [NSValue valueWithPointer:CFRunLoopGetCurrent()]; 
    [info setObject:runLoop forKey:kRunLoop]; 
    NSThread *targetThread = [NSThread isMainThread] ? m_thread : [NSThread mainThread]; 
    [self performSelector:@selector(executeOperation:) onThread:targetThread withObject:info waitUntilDone:NO]; 
    CFRunLoopRun();  // 开始一个嵌套的RunLoop 
} 
 
- (void)executeOperation:(NSMutableDictionary*)info 
{ 
    NSNumber* number = [info objectForKey:kParameter]; 
    CFRunLoopRef runLoop = [(NSValue*)[info objectForKey:kRunLoop] pointerValue]; 
    int count = [number intValue]; 
    NSLog(@"count is reduced to %d on %@", --count, [NSThread currentThread].name); 
    if (count) 
    { 
        number = [NSNumber numberWithInt:count]; 
        [info setObject:number forKey:kParameter]; 
        [self sendSynchronousMessageToTheOtherThread:info]; 
    } 
    CFRunLoopStop(runLoop);  // 停止掉RunLoop栈栈顶的RunLoop 
} 
 
- (void)buttonClicked:(UIButton*)button 
{ 
    static bool mainThreadFirst = false; 
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kLevelsOfNesting], kParameter, nil]; 
    mainThreadFirst = !mainThreadFirst; 
    if (mainThreadFirst) 
    { 
        [self sendSynchronousMessageToTheOtherThread:dictionary]; 
        NSLog(@"-------Because of nesting synchonization, this log is printed at the end.-------"); 
    } 
    else 
        [self performSelector:@selector(sendSynchronousMessageToTheOtherThread:) onThread:m_thread withObject:dictionary waitUntilDone:NO]; 
     
} 
 
- (void)secondaryThreadMain:(id)para 
{ 
    @autoreleasepool { 
        [NSThread currentThread].name = @"Secondary Thread"; 
        NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 
        NSThread *thread = [NSThread currentThread]; 
        NSPort *port = [NSMachPort port];       // 阻塞RunLoop 
        [currentRunLoop addPort:port forMode:NSDefaultRunLoopMode]; 
        NSDate *distantFuture = [NSDate distantFuture]; 
         
        while (!thread.isCancelled) 
        { 
            NSAutoreleasePool *pool = [NSAutoreleasePool new]; 
            NSLog(@"RunLoop runs once");     
            [currentRunLoop runUntilDate:distantFuture]; // 这里会阻塞,直到有事件触发 
            [pool drain]; 
        } 
         
        [currentRunLoop removePort:port forMode:NSDefaultRunLoopMode]; 
    } 
} 
 
- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 
 
@end 

运行demo工程,点击一下button,看看log输出就懂有什么用了。或者在第61行

CFRunLoopStop(runLoop);  // 停止掉RunLoop栈栈顶的RunLoop 

加个断点,看看堆栈,会在两个线程都看到嵌套的RunLoop.堆栈截图如下:



实用例子
子线程想创建一个UIView,发同步消息到主线程创建(UIKit对象都得主线程操作),主线程创建过程中又需要去子线程执行一段代码做些判断,这又需要主线程发同步消息回子线程;如果使用锁技术,这就是死锁。
RunLoop的东西很复杂,认真看文档最实际了。也可以重点看CFRunLoopRun和CFRunLoopStop两个函数。

附:
关于NSRunLoop和CFRunLoop需要注意的地方:
Warning:  The NSRunLoop class is generally not considered to be thread-safe and its methods should only be called within the context of the current thread. You should never try to call the methods of an NSRunLoop object running in a different thread, as doing so might cause unexpected results.
Although they are not toll-free bridged types, you can get a CFRunLoopRef opaque type from an NSRunLoop object when needed. The NSRunLoop class defines a getCFRunLoop method that returns a CFRunLoopRef type that you can pass to Core Foundation routines. Because both objects refer to the same run loop, you can intermix calls to the NSRunLoop object and CFRunLoopRef opaque type as needed.
Thread safety varies depending on which API you are using to manipulate your run loop. The functions in Core Foundation are generally thread-safe and can be called from any thread. If you are performing operations that alter the configuration of the run loop, however, it is still good practice to do so from the thread that owns the run loop whenever possible.

The Cocoa NSRunLoop class is not as inherently thread safe as its Core Foundation counterpart. If you are using the NSRunLoop class to modify your run loop, you should do so only from the same thread that owns that run loop. Adding an input source or timer to a run loop belonging to a different thread could cause your code to crash or behave in an unexpected way.
目录
相关文章
|
3月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
129 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
1月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
2月前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
2月前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
3月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
57 1
|
3月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
3月前
多线程通信和同步的方式有哪些?
【10月更文挑战第6天】
142 0
|
3月前
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
32 0
|
4月前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
5月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
108 1