2017-05-24 15 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'是零,所以你的代碼不會做任何事情 – 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"); 
     } 
    }); 
} 

最終計數,而你正在使用快速列舉會給崩潰變異數組,但突變沒有按在這種情況下,甚至不得不從另一條線索來;只是在枚舉循環中改變數組會導致崩潰。

相關問題