多線程-訪問公共資源引發數據安全分析

  • 共享資源:
    一塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一塊資源
    比如多個線程訪問統一個對象、同一個變量、同一個文件

當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題

之所以會出現數據錯亂的問題,是由于CPU的工作特性,隨機在不同的線程間進行調度.

先通過一段代碼演示多線程下訪問公共資源引發數據錯亂的情景:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController{
    
    NSInteger _totalCounts;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    _totalCounts = 10;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    
    [thread1 start];
    [thread2 start];
}

- (void)demo{
    
    for (int i = 0; i < 10 ;i ++) {
        
        if (_totalCounts > 0) {
            
            _totalCounts--;
            NSLog(@"%zd",_totalCounts);
            
        }else{
            
            NSLog(@"停止");
            break;
        }
    }
    
}

@end

這段代碼中,兩條子線程分別訪問同一個成員變量并修改該成員變量的值,這里循環的次數比較少,如果想要出現數據錯亂線程更明顯一些,可以將循環次數變大,排除正常結果,在出現數據錯亂的情景中,有兩種典型的情況:

開始時先輸出8,后輸出9

2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 8
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 9
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 7
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 6
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 5
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 4
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 3
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 2
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 1
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 0
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 停止
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 停止

分析:

多線程訪問公共資源_1.png

1.假設藍色線程先被執行,初始值10,進入循環
2._totalCounts--; 藍色線程執行自減,此時公共資源的值變為9
3.在執行完自減,并在NSLog輸出前,該線程進入阻塞狀態,CPU切換到粉色線程執行任務
4.粉色線程初始值9,進入循環
5._totalCounts--; 粉色線程同樣執行自減,此時公共資源的值變為8
6.粉色線程繼續執行NSLog,輸出結果8,粉色線程進入阻塞狀態
7.再次切換回藍色線程執行下一句代碼NSLog,之前記錄的結果為9,所以打印結果為9

從而出現先打印8,后打印9的現象

開始時連續輸出兩個9

這種情況模擬時出現的概率比較低,直接分析結果:

多線程訪問公共資源_2.png

1.假設藍色線程先被執行,初始值10,進入循環
2.在執行自減操作前藍色線程就進入阻塞狀態,此時公共資源的值仍為10
3.CPU切換到粉色線程執行任務,粉色線程初始值10,進入循環
4._totalCounts--; 粉色線程執行自減,此時公共資源的值變為9
5.粉色線程繼續執行NSLog,輸出結果9,粉色線程進入阻塞狀態
6.再次切換回藍色線程,根據上一次操作記錄(初始值10,滿足條件進入循環)繼續執行任務,執行自減操作,此時totalCounts由10變為9
7.執行NSLog,打印結果為9

從而導致出現開始連續兩次打印9 的現象

正因為CPU的這種工作特性,如果使用多線程,不對公共資源做處理,就會造成數據安全問題,除了上述的兩種典型情況外,還有其他情況,例如:

2016-07-30 23:16:04.960 多線程訪問共享資源[1725:297008] 8
2016-07-30 23:16:04.960 多線程訪問共享資源[1725:297009] 9
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 7
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297009] 6
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 5
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297009] 4
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 3
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 2
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297008] 1
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297008] 停止
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 0
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 停止
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容