想要不阻塞当前线程的情况下同时执行多个任务
dispatch_queue_t queueConcurrent = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(queueConcurrent,^{
NSLog(@"curThread = %@,i = %d",[NSThread currentThread],i);
});
}
在同时执行多个任务情况下。因为同时执行多个任务情况下哪个任务先执行完不一定,因此需要排序
在同时执行多个任务情况下。这些任务执行多执行完毕后要执行相关逻辑代码
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queueConcurrent = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_group_async(group,queueConcurrent,^{
sleep(0.5);
NSLog(@"curThread = %@,i = %d",[NSThread currentThread],i);
});
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任务执行完毕!");
});
在同时执行多个任务情况下。想要一个线程等待一组线程执行完毕后这个线程在执行相关逻辑代码(线程与线程组的同步)
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queueConcurrent = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_group_async(group,queueConcurrent,^{
sleep(0.5);
NSLog(@"curThread = %@,i = %d",[NSThread currentThread],i);
});
}
dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
NSLog(@"线程组执行完毕!");
在同时执行多个任务情况下。这些任务同时访问了共同的数据,导致了数据竞争或者非法访问内存导致程序崩溃。(写入与写入同时进行会导致内存非法访问程序崩溃。写入与读取同时进行,因为涉及到先后关系,会出现数据竞争问题)
0. 在这种情况下一共有三种解决办法,推荐使用dispatch_barrier_async配合dispatch_queue_create创建的并发队列。
__block int a = 3;
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.test.queueConcurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queueConcurrent, ^{
//读取
sleep(1);
NSLog(@"任务1 a = %d",a);
});
dispatch_async(queueConcurrent, ^{
//读取
NSLog(@"任务2 a = %d",a);
});
dispatch_async(queueConcurrent, ^{
//读取
NSLog(@"任务3 a = %d",a);
});
dispatch_barrier_async(queueConcurrent, ^{
//写入
a = 5;
});
dispatch_async(queueConcurrent, ^{
//读取
NSLog(@"任务4 a = %d",a);
});
dispatch_async(queueConcurrent, ^{
//读取
NSLog(@"任务5 a = %d",a);
});
利用串行队列
利用信号量
NSMutableArray *arrM = [NSMutableArray array];
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
for (int i = 0; i < 1000; i++) {
dispatch_async(queueConcurrent, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[arrM addObject:[NSNumber numberWithInt:i]];
dispatch_semaphore_signal(semaphore);
});
}
线程同步
dispatch_semaphore_t semaphone = dispatch_semaphore_create(0);
dispatch_queue_t queue1 = dispatch_get_global_queue(0, 0);
dispatch_async(queue1, ^{
//线程1
dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);
dispatch_async(queue2, ^{
//线程2
sleep(3.0);
NSLog(@"线程2执行完毕");
dispatch_semaphore_signal(semaphone);
});
dispatch_semaphore_wait(semaphone, DISPATCH_TIME_FOREVER);
NSLog(@"线程1等待线程2完毕");
});
想要在不阻塞当前线程的情况下,串行的有序的执行任务
dispatch_queue_t queueSerial = dispatch_queue_create("com.test.queueSerial", NULL);
for (int i = 0; i < 10; i++) {
dispatch_async(queueSerial, ^{
NSLog(@"curThread = %@, i = %d",[NSThread currentThread],i);
});
}
想要在阻塞当前线程的情况下,串行的有序的执行任务
dispatch_queue_t queueSerial = dispatch_queue_create("com.test.queueSerial", NULL);
for (int i = 0; i < 10; i++) {
dispatch_sync(queueSerial, ^{
NSLog(@"curThread = %@, i = %d",[NSThread currentThread],i);
});
}
想要挂起或者恢复一个由dispatch_queue_create函数创建的队列
- (void)viewDidLoad {
[super viewDidLoad];
queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
dispatch_suspend(queue);
dispatch_async(queue, ^{
NSLog(@"fsa");
});
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
dispatch_resume(queue);
}
想要创建一个线程安全的单利
+ (instancetype)shareInstance{
static ViewController *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
想要大致延时一定时间去执行相关逻辑代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)5*NSEC_PER_SEC), queue, ^{
NSLog(@"curThread = %@, 执行任务",[NSThread currentThread]);
});
```
{
dispatch_source_t sourceTimer;
}
- (void)viewDidLoad {
[super viewDidLoad];
//dispatch_source实现timer
sourceTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(sourceTimer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)5*NSEC_PER_SEC), 1*NSEC_PER_SEC, 1*NSEC_PER_SEC);
dispatch_source_set_event_handler(sourceTimer, ^{
NSLog(@"开始执行---");
});
dispatch_source_set_cancel_handler(sourceTimer, ^{
NSLog(@"结束执行---");
});
dispatch_resume(sourceTimer);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
dispatch_suspend(sourceTimer);
}
```
dispatch_source的定时器和NSTimer对比。
dispatch_source的定时器更精确,因为NSTimer依靠NSRunlopp,NSRunloop要处理好多事导致NSTimer不精确。而dispatch_source的定时器是系统内核事件优先级较高所以定时更加精确。
GCD的dispatch_source其实是支持启动和取消的。但是dispatch_queue不支持。
在进行网络编程时候不应该每次都创建新的子线程
因为每次网络请求都创建新的子线程,那么很快就会把系统的线程用尽,也会占用大量的内存。每次创建还会很耗时。也就是说这种做法又耗时又耗内存,又可能把系统的线程用尽。所以AFN的早期版本使用了线程常驻。
造成死锁的条件是相互等待。
比如在主队列中执行同步函数会造成死锁。
在一个串行队列的任务里嵌套一个任务,这个任务也是用的这个串行队列,并且使用了同步函数,这时候会造成死锁。
开发相关
问利用多线程实现多个图片的下载合并或者问上传多个图片到服务器之后排序
分析:其实就是利用多线程并发请求,之后再排序的问题。
代码:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arrM = [NSMutableArray array];//准备接收执行完的任务结果数组
NSArray *arr = @[@"http://img.zcool.cn/community/0117e2571b8b246ac72538120dd8a4.jpg@1280w_1l_2o_100sh.jpg",
@"http://img.zcool.cn/community/01f09e577b85450000012e7e182cf0.jpg@1280w_1l_2o_100sh.jpg",
@"http://img.zcool.cn/community/0125fd5770dfa50000018c1b486f15.jpg@1280w_1l_2o_100sh.jpg",
@"http://pic5.nipic.com/20100221/2839526_090902782678_2.jpg"
];//下载图片任务地址数组(这里往往是多个任务地址)
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
dispatch_group_async(group, queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:arr[idx]]];
UIImage *img = [UIImage imageWithData:data];
//创建一个字典用于数组排序
NSDictionary *dict = @{@"order":[NSString stringWithFormat:@"%ld",idx],@"img":img};
[arrM addObject:dict];
});
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"name = %@",[NSThread currentThread]);
//结果数组进行排序
NSArray *arrSorted = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES]];
NSArray *arrResult = [arrM sortedArrayUsingDescriptors:arrSorted];
[self displayImg:arrResult];
});
}
- (void)displayImg:(NSArray *)arrImg{
[arrImg enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *dict = obj;
UIImage *img = dict[@"img"];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, idx*150, self.view.frame.size.width, 150.0)];
imgView.image = img;
[self.view addSubview:imgView];
}];
}