多线程与通知

Posted 火海夕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程与通知相关的知识,希望对你有一定的参考价值。

总结:

1、同一线程,添加多个观察者或者发送多次通知,就会响应多次方法

2、不管创建在哪个线程,发送在哪个线程接收就在哪个线程

3、接收在哪个线程可以由添加方法发来控制

4、接收在哪个线程可以由添加runloop端口的方法来控制

#import "ViewController.h"
#define TEST_NOTIFICATION @"TestNotification"
@interface ViewController ()<NSMachPortDelegate>
@property (nonatomic) NSMutableArray    *notifications;         // 通知队列
@property (nonatomic) NSThread          *notificationThread;    // 期望线程
@property (nonatomic) NSLock            *notificationLock;      // 用于对通知队列加锁的锁对象,避免线程冲突
@property (nonatomic) NSMachPort        *notificationPort;      // 用于向期望线程发送信号的通信端口
@end

@implementation ViewController
- (void)viewDidLoad 
    [super viewDidLoad];
    //    [self test5];
    //    [self test4];
    //    [self test3];
    //    [self test2];
    //    [self test1];


#pragma mark -添加一个观察者,发送两次响应两次
-(void)test5
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(firstNotification:) name:TEST_NOTIFICATION object:nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];

#pragma mark - 添加多个观察者,发送一次响应两次
-(void)test4
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(firstNotification:) name:TEST_NOTIFICATION object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(firstNotification:) name:TEST_NOTIFICATION object:nil];

    [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];

#pragma mark - 发送在子线程,接收在主线程(可以指定某一个线程,不一定非要主线程)
-(void)test3
    [[NSNotificationCenter defaultCenter] addObserverForName:TEST_NOTIFICATION object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) 
            NSLog(@"接收和处理通知的线程%@", [NSThread currentThread]);
        ];
    dispatch_async(dispatch_get_global_queue(0, 0), ^
        [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
        NSLog(@"发送通知的线程为%@", [NSThread currentThread]);
    );

#pragma mark - 发送在子线程,接收在主线程(接收在添加port所在loop的线程)

-(void)test2
    NSLog(@"当前线程 = %@", [NSThread currentThread]);
    
    // 初始化
    self.notifications = [[NSMutableArray alloc] init];
    self.notificationLock = [[NSLock alloc] init];
    
    self.notificationThread = [NSThread currentThread];
    self.notificationPort = [[NSMachPort alloc] init];
    self.notificationPort.delegate = self;
    
    // 往当前线程的run loop添加端口源
    // 当Mach消息到达而接收线程的run loop没有运行时,则内核会保存这条消息,直到下一次进入run loop
    [[NSRunLoop currentRunLoop] addPort:self.notificationPort
                                forMode:(__bridge NSString *)kCFRunLoopCommonModes];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(secondNotification:) name:TEST_NOTIFICATION object:nil];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        NSLog(@"发送线程 = %@", [NSThread currentThread]);
        [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
    
    );

//notificationPort代理方法
- (void)handleMachMessage:(void *)msg 
    NSLog(@"%s",__func__);

    [self.notificationLock lock];
    
    while ([self.notifications count]) 
        NSNotification *notification = [self.notifications objectAtIndex:0];
        [self.notifications removeObjectAtIndex:0];
        [self.notificationLock unlock];
        [self secondNotification:notification];
        [self.notificationLock lock];
    ;
    
    [self.notificationLock unlock];

    
- (void)secondNotification:(NSNotification *)notification 
    NSLog(@"%s",__func__);
    if ([NSThread currentThread] != _notificationThread) 
        // Forward the notification to the correct thread.
        [self.notificationLock lock];
        [self.notifications addObject:notification];
        [self.notificationLock unlock];
        [self.notificationPort sendBeforeDate:[NSDate date]
                                   components:nil
                                         from:nil
                                     reserved:0];

    
    else 
        // Process the notification here;
        NSLog(@"接收线程 = %@", [NSThread currentThread]);
        NSLog(@"通知流程结束");
    

#pragma mark - 创建在同一个线程,发送和接收在一个线程

-(void)test1
        NSLog(@"当前线程为%@", [NSThread currentThread]);//0
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(firstNotification:) name:TEST_NOTIFICATION object:nil];

        dispatch_async(dispatch_get_global_queue(0, 0), ^
            [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
            NSLog(@"发送通知的线程为%@", [NSThread currentThread]);//1
        );


- (void)firstNotification:(NSNotification *)notification 
    NSLog(@"接收线程%@", [NSThread currentThread]);//1

@end

以上是关于多线程与通知的主要内容,如果未能解决你的问题,请参考以下文章

多线程与通知

Java多线程之三volatile与等待通知机制示例

Java 多线程 :入门- 线程间协作:挂起当前线程(wait)与通知其他线程继续执行(notify notifyAll)

java多线程系列

多线程核心点

34.条件变量与多线程(单播与多播)