在iOS中,多线程使用较多的API是: NSOperationQueue 和 GCD 。其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实现的 OC的API,GCD使用方便,但代码较多,更致命的缺点如果是耗时操作,则无法取消任务,而NSOperationQueue则可以
问题1 : 如果有N个任务,如何使N个任务依次执行?? NSOperationQueue 可以设置最大并发数,并进行任务依赖,GCD可以使用信号量来进行多线程通信。信号量控制主要分为三个步骤,设置信号初始值,降低信号量,增加信号量。
方案: dispatch_semaphore_t
设置信号量初始值,该值可以理解为一次最多执行的任务数)(下图初始值为orig,信号量变化值为value)。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
降低信号量,每次执行,初始值信号量就降低1,如果初始值降为0,则线程阻塞,该线程为等待线程(所 以此函数 避免在主线程中使用,避免阻塞主线程)(上图value值减小)
dispatch_semaphore_signal(semaphore) 增加信号量,每次执行,初始值信号量就增加1,如果初始值不为0,则 唤醒一个等待线程,此函数和上面的降低信号量函数成对使用(上图value值增加1)
测试代码:
dispatch_semaphore_t semaphore =dispatch_semaphore_create(3);
dispatch_queue_t quene =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
NSLog(@"================= 1");
dispatch_async(quene, ^{
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@"task_1_1");
sleep(2);
dispatch_semaphore_signal(semaphore);
NSLog(@"task_1_2");
});
NSLog(@"================= 2");
dispatch_async(quene, ^{
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@"task_2_1");
sleep(2);
dispatch_semaphore_signal(semaphore);
NSLog(@"task_2_2");
});
NSLog(@"================= 3");
dispatch_async(quene, ^{
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@"task_3_1");
sleep(1);
dispatch_semaphore_signal(semaphore);
NSLog(@"task_3_2");
});
举个例子: 假如一个屋子只能进去3个人(设置信号量初始值),现在屋子里没有人(没有任务执行),这时
每次进入一个人,屋子能进去的人就减少一个(信号量减一),当屋子里三个人的时候(信号值为0),
此时如果再来人,则需要等待(等待线程),如果从屋子里出来一个人,则就有一个人能够进入(信号
值增加一,唤醒一个等待线程执行任务),当屋子里的人全都出来时,则信号值为初始值3;
NSOperation 子类使用
NSOperation 是一个抽象类,需要使用其子类NSInvocationOperation 和 NSBlockOperation
NSInvocationOperation *invocationO = [[NSInvocationOperationalloc] initWithTarget:selfselector:@selector(invocationOperationAction)object:nil];
[invocationO start];// 需要使用start方法进行任务执行,但线程是在执行的所在线程(在主线程就是主线程,而不会开辟线程)
NSBlockOperation *blockO = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block 1 %@", [NSThreadcurrentThread]); // 主线程 block 1 <NSThread: 0x60c000073f40>{number = 1, name = main}
}];
[blockO addExecutionBlock:^{
NSLog(@"block 2 %@", [NSThreadcurrentThread]); // 子线程 block 2 <NSThread: 0x608000267040>{number = 3, name = (null)}
}];
[blockO start]; // 执行
NSOperationQueue 使用
// 创建主队列
NSOperationQueue *mainOperation = [NSOperationQueue mainQueue];
[mainOperation addOperationWithBlock:^{
NSLog(@"是否主队列 %@", [NSThreadcurrentThread]); // 是否主队列 <NSThread: 0x60c000073f40>{number = 1, name = main}
}];
// 队列并发和串行
NSOperationQueue *asyOperation = [[NSOperationQueuealloc] init]; // 非主队列
asyOperation.maxConcurrentOperationCount =3; // 如果最大并发数大于1,则该队列为并发队列,为1时,该对列为串行队列。
// 操作依赖
NSBlockOperation *operationO_1 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"operationO_1");
}];
NSBlockOperation *operationO_2 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"operationO_2");
}];
NSBlockOperation *operationO_3 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"operationO_3");
}];
NSOperationQueue *operationQueue_3 = [[NSOperationQueuealloc] init];
operationQueue_3.maxConcurrentOperationCount =2;
[operationO_2 addDependency:operationO_1]; // 依赖 任务operationO_2 在 operationO_1 之后执行
[operationO_3 addDependency:operationO_2];
[operationQueue_3 addOperation:operationO_2];
[operationQueue_3 addOperation:operationO_1];
[operationQueue_3 addOperation:operationO_3];
// 取消任务
[operationO_1 cancel];// 取消单个任务 调用对象为NSOperation
[operationQueue_3 cancelAllOperation];// 取消所有任务 调用对象为NSOperationQueue
// 队列的暂停与恢复
[operationQ_2 setSuspended:YES]; // 队列暂停,挂起队列
------------------------------ 如有错误,请进行纠正 ------------------------------------