上一篇:多线程研究一:NSOperation实现GCD group依赖
本文Sample Github: MultithreadSample
前言
在多线程处理中,有时候会遇到虽然已经取消了队列里的所有Operation,但是如果Operation已经开始执行,cancle就已经不起作用了,这个会导致数据错乱乃至APP崩溃闪退的异常问题
解决方法:利用NSBlockOperation
执行block时,将该NSBlockOperation
使用__block
到block里,然后对当前的Operation判断是否已经被取消,具体代码实现如下:
Objective-C实现方式
+ (void) testOperationCancleOperationBlock
{
// 打印当前线程
//NSLog(@"###oc-operation1-begin-currentThread---%@",[NSThread currentThread]);
NSMutableArray *ops = [NSMutableArray array];
// 需要循环遍历添加执行任务的场景
for (int i=0;i<10;i++) {
int temps = (arc4random() % 5) + 1;
NSBlockOperation *op = [LFCustomBlockOperationOC new];
__weak typeof(NSBlockOperation) *weakOp = op;
[op addExecutionBlock:^{
NSLog(@"###oc-cancle-aaa %d %@ isCancelled:%@",i,weakOp,weakOp.isCancelled?@"true":@"false");
if (weakOp.isCancelled){
return ;
}
[NSThread sleepForTimeInterval:temps];
NSLog(@"###oc-cancle-bbb %d %@ isCancelled:%@",i,weakOp,weakOp.isCancelled?@"true":@"false");
if (weakOp.isCancelled){
return ;
}
NSLog(@"###oc-cancle-ccc i:%d-wait:%d-thread:%@",i,temps,NSThread.currentThread);
}];
[ops addObject:op];
}
// 不是遍历添加的需要单独添加的任务
TestGCDOperationOC *target = [TestGCDOperationOC new];
NSOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:target selector:@selector(hello:) object:@"1"];
[ops addObject:op1];
// 其他Operation都执行完后再执行的Operation
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"###oc-cancle- ++++++thread:%@",NSThread.currentThread);
});
}];
// 最后执行的任务对其他所有任务都添加依赖
for (NSOperation *op in ops) {
[op2 addDependency:op];
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[ops addObject:op2];
// 添加到任务队列中执行
[queue addOperations:ops waitUntilFinished:false];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[queue cancelAllOperations];
});
}
Swift实现方式
class func testOperationCancleOperationBlock() -> Void
{
var ops: [Operation] = []
// 需要循环遍历添加执行任务的场景
for i in 0..<10 {
let temps:Int = Int(arc4random_uniform(3))+1
let operation: BlockOperation = LFCutomeBlockOperationSwift()
weak var weakOpe = operation
operation.addExecutionBlock {
print("###swift-cancle-aaa i:\(i)-wait:\(temps)-isCancle:\(String(describing: weakOpe?.isCancelled))")
if weakOpe?.isCancelled ?? false {
return
}
sleep(UInt32(temps))
print("###swift-cancle-bbbx i:\(i)-wait:\(temps)-isCancle:\(String(describing: weakOpe?.isCancelled))")
if weakOpe?.isCancelled ?? false {
print("###swift-cancle-bbby i:\(i)-wait:\(temps)-isCancle:\(String(describing: weakOpe?.isCancelled))")
return
}
print("###swift-cancle-ccc i:\(i)-wait:\(temps)-thread:\(Thread.current)")
}
ops.append(operation)
}
// 不是遍历添加的需要单独添加的任务
let op1 = BlockOperation {
print("###swift-cancle -------\(Thread.current)")
}
ops.append(op1)
let op2 = BlockOperation {
DispatchQueue.main.async {
print("###swift-cancle +++++-\(Thread.current)")
}
}
// 最后执行的任务对其他所有任务都添加依赖
for op in ops {
op2.addDependency(op)
}
ops.append(op2)
let queue = OperationQueue()
// 添加到任务队列中执行
queue.addOperations(ops, waitUntilFinished: false)
DispatchQueue.global().asyncAfter(deadline: .now()+2) {
queue.cancelAllOperations()
}
}
网友评论