需求:异步操作,比如网络请求,要求异步回调后拿到这个值,然后返回这个值
需求分析:实际上这个应用场景是著名网络请求框架AFNNetworking
一个
- (NSString *)httpNet{
// 1.创建信号量
//传入的参数为long 参数value必须大于或等于0,一般情况都是传0
dispatch_semaphore_t signal = dispatch_semaphore_create(0.0);
__block NSString *objectID;
// 模拟block异步
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 异步的耗时操作,比如:睡眠3秒
[NSThread sleepForTimeInterval:3];
objectID = @"222";
NSLog(@"objectID=%@",objectID);
// 2.发送信号量
// 这个函数会使传入的信号量dsema的值加1
dispatch_semaphore_signal(signal);
});
// 这个函数的作用是这样的,如果dsema信号量的值大于0,该函数所处线程就继续执行下面的语句,并且将信号量的值减1
// 这个函数会使传入的信号量dsema的值减1;
// 如果desema的值为0,那么这个函数就阻塞当前线程等待timeout
// 关键点:如果想阻塞线程,那么所传的参数signal值必须为0,异步回调成功后,想要取消阻塞线程,需要信号量dsema的值加1,那么就会自动跳转到`dispatch_semaphore_wait`这行代码执行,这行代码会使信号量dsema的值减1;
// 3.等待信号量
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
// 如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句
NSLog(@"objectID=%@",objectID);
return objectID;
}
步骤
- 1.创建信号量
dispatch_semaphore_create(0.0)
- 2.发送信号量
dispatch_semaphore_signal(signal)
- 3.等待信号量
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER)
总结: 通常等待信号量和发送信号量的函数是成对出现的,在异步线程中使用 解决问题:并发队列中的任务同步执行的要求/用信号量机制使异步线程完成同步操作
面试题:AFNetWorking与dispatch_semaphore_t能共存吗?如图
发生了死锁
原因: AFN框架已经把success
和failure
的回调放在了主线程中. 所以程序在走到dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOEVER)
这句代码的时候, 已经将主线程锁住了, 所以同处于主线程的success
和failure
的回调block压根就不会走, 所以同时放在主线程中的dispatch_semaphore_signal(semaphore)
同样也不会走, 那么信号量的
value
值也不可能增大, 所以value
值一直为0, 那么被锁住的主线程就永远锁住了