2017-05-24 11 views
0

아래 코드에서 우리는 두 개의 동시 대기열에 의해 변이 된 가변 배열을가집니다. 동시 대기열은 스레드로부터 안전하지 않으므로이 코드는 이상적으로 중단되어야하지만 예외 나 충돌없이 실행됩니다.전역 동시 대기열을 사용하여 두 개의 다른 스레드에서 배열을 변이시킬 때 충돌이 발생하지 않습니다.

이 동작을 이해하는 데 도움을주십시오. 어떤 도움을 많이 주시면 감사하겠습니다 :-)

@interface ViewController() 
    @property(nonatomic, strong) NSMutableArray *arr; 
    @end 

    @implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    self.arr = [NSMutableArray new]; 
} 

-(void)viewDidAppear:(BOOL)animated{ 

     [super viewDidAppear:animated]; 

     __weak typeof(self) weakSelf = self; 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      for (int i = 0; i < 20000; i++) { 
        [weakSelf.arr addObject:[NSNumber numberWithInt:i]]; 
        NSLog(@"Added %@", [weakSelf.arr lastObject]); 
       } 

      NSLog(@"Final count %ld", [self.arr count]); 
     }); 

     [self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1]; 
    } 

    -(void)removeObjects{ 
     __weak typeof(self) weakSelf = self; 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      for (int i = 0; i < 1000; i++) { 
       if (weakSelf.arr.count > 1) { 
        [weakSelf.arr removeObjectAtIndex:0]; 
       } 
       NSLog(@"Remove object"); 
      } 
     }); 
    } 

    @end 
+0

아마도 당신은 단지 운이 좋았을 것입니다. 내가 틀렸을 수도 있지만 코드가 충돌하는 것을 보장 할 수 있는지 확실하지 않습니다. 제 생각에 충돌이 일어나지 않을 것이라고는 생각하지 않습니다 ... 정의에 따르면, 당신은 경주 조건에 의존해서는 안되며 ... –

+0

@ NicolasMiari 귀하의 의견을 보내 주셔서 감사합니다. 이 코드를 여러 번 실행 해 보았습니다. 한번 예외가 발생하지 않았습니다. 나는 매번 운이 좋을 수 없다. 블록 범위와 같은 예외를 피하는 데 도움이 될 수있는 다양한 가능성을 파악하려고 시도했지만 정확한 내용을 결론 지을 수는 없습니다. – Say2Manuj

+0

실제로 배열을 어디에 할당합니까? 'arr'은 nil이므로 코드는 아무 것도하지 않습니다. – Paulw11

답변

0

하나의 리소스에 동시 액세스한다는 것은 충돌이 보장된다는 의미는 아닙니다. 이것은 "행운"과 아무 관련이 없습니다. 아마도 충돌이 발생하지 않는 상황에서 코드가 체계적으로 실행됩니다.

"스레드로부터 안전하지 않은"것은 "충돌합니다"를 의미하지 않습니다. 오작동이 발생할 수 있습니다.

0

NSMutableArray에 동시 액세스해도 명시 적으로 충돌이 발생하지 않지만 배열이 손상되어 잘못된 데이터로 인해 응용 프로그램이 중단 될 수 있습니다. 러닝 당신이 최종 카운트 약간 다른 값을 얻을

-(void)viewDidAppear:(BOOL)animated{ 

    [super viewDidAppear:animated]; 

    __weak typeof(self) weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 
     for (int i = 0; i < 20000; i++) { 
      NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]); 
      [weakSelf.arr insertObject:[NSNumber numberWithInt:i] atIndex:randomIndex]; 
      NSLog(@"Added %@", weakSelf.arr[randomIndex]); 
     } 

     NSLog(@"Final count %ld", [self.arr count]); 
    }); 

    [self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1]; 
} 

-(void)removeObjects{ 
    __weak typeof(self) weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     for (int i = 0; i < 1000; i++) { 
      if (weakSelf.arr.count > 1) { 
       NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]); 
       [weakSelf.arr removeObjectAtIndex:randomIndex]; 
      } 
      NSLog(@"Remove object"); 
     } 
    }); 
} 

때마다 :

은이 코드 약간 수정 된 버전을 고려하십시오.

배열 액세스가 스레드 안전 할 @synchronized를 추가 할 경우 당신은 항상 당신이 충돌을 줄 것이다 빠른 열거를 사용하는 동안 배열을 변경했을 19000

-(void)viewDidAppear:(BOOL)animated{ 

    [super viewDidAppear:animated]; 

    __weak typeof(self) weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 
     for (int i = 0; i < 20000; i++) { 
      @synchronized (self.arr) { 

      NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]); 
      [weakSelf.arr insertObject:[NSNumber numberWithInt:i] atIndex:randomIndex]; 
      NSLog(@"Added %@", weakSelf.arr[randomIndex]); 
      } 
     } 

     NSLog(@"Final count %ld", [self.arr count]); 
    }); 

    [self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1]; 
} 

-(void)removeObjects{ 
    __weak typeof(self) weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     for (int i = 0; i < 1000; i++) { 
      if (weakSelf.arr.count > 1) { 
       @synchronized (self.arr) { 

       NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]); 
       [weakSelf.arr removeObjectAtIndex:randomIndex]; 
       } 
      } 
      NSLog(@"Remove object"); 
     } 
    }); 
} 

의 최종 수,하지만 돌연변이 아무튼를 얻을 수 이 경우에는 다른 스레드의 스레드 여야합니다. 단순히 열거 루프에서 배열을 변경하면 충돌이 발생합니다.