多線程同步菩掏?這個(gè)有什么意義呢魂角。
多線程編程里面,一些敏感數(shù)據(jù)不允許被多個(gè)線程同時(shí)訪問智绸,此時(shí)就使用同步訪問技術(shù)野揪,保證數(shù)據(jù)在任何時(shí)刻,最多有一個(gè)線程訪問瞧栗,以保證數(shù)據(jù)的完整性斯稳。
先來個(gè)概念性的東西,理解下
信號(hào)量
信號(hào)量(Semaphore)迹恐,有時(shí)被稱為信號(hào)燈挣惰,是在多線程環(huán)境下使用的一種設(shè)施,是可以用來保證兩個(gè)或多個(gè)關(guān)鍵代碼段不被并發(fā)調(diào)用。在進(jìn)入一個(gè)關(guān)鍵代碼段之前憎茂,線程必須獲取一個(gè)信號(hào)量珍语;一旦該關(guān)鍵代碼段完成了,那么該線程必須釋放信號(hào)量竖幔。其它想進(jìn)入該關(guān)鍵代碼段的線程必須等待直到第一個(gè)線程釋放信號(hào)量板乙。為了完成這個(gè)過程,需要?jiǎng)?chuàng)建一個(gè)信號(hào)量VI赏枚,然后將Acquire Semaphore VI以及Release Semaphore VI分別放置在每個(gè)關(guān)鍵代碼段的首末端亡驰。確認(rèn)這些信號(hào)量VI引用的是初始創(chuàng)建的信號(hào)量。
可以簡(jiǎn)單理解成線程同步作用和加鎖相似饿幅。其實(shí)同步和加鎖是有區(qū)別的。只是線程同步的效果和加鎖之后的作用一樣戒职。具體下一篇會(huì)有解釋栗恩。不廢話了,直奔代碼
先模擬用戶去買票洪燥,一共提供三條通道磕秤,買票。
沒有進(jìn)行線程同步
上述是開啟三條線程捧韵,然后都是同時(shí)去對(duì)數(shù)據(jù)進(jìn)行減減操作市咆。會(huì)發(fā)現(xiàn),數(shù)據(jù)出現(xiàn)異常再来。那是因?yàn)槊衫迹鄺l線程同時(shí)訪問這個(gè)數(shù)據(jù)時(shí)候,該線程只是讀取到他訪問時(shí)候的數(shù)據(jù)芒篷,若此時(shí)還有其他線程對(duì)該數(shù)據(jù)進(jìn)行操作的話搜变。則這個(gè)數(shù)據(jù)就會(huì)出現(xiàn)異常。
一:GCD中的信號(hào)量實(shí)現(xiàn)線程同步
- (void)viewDidLoad {
[super viewDidLoad];
// 實(shí)例類person
self.person = [[Person alloc] init];
self.person.num = 100;
//dispatch_semaphore_create(1) 創(chuàng)建一個(gè)信號(hào)量针炉,設(shè)置信號(hào)量的資源數(shù)0表示沒有資源挠他,調(diào)用dispatch_semaphore_wait會(huì)立即等待。
//dispatch_semaphore_signal 發(fā)送一個(gè)信號(hào)會(huì)讓信號(hào)量+1
//dispatch_semaphore_wait 等待信號(hào)會(huì)讓信號(hào)量 —1
self.semaphore = dispatch_semaphore_create(1);
//模擬三條不同的網(wǎng)絡(luò)去搶票
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeActionA) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timeActionB) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeActionC) userInfo:nil repeats:YES];
}
- (void)timeActionA{
// 線程A
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//等待信號(hào)篡帕,當(dāng)信號(hào)總量少于0的時(shí)候就會(huì)一直等待殖侵,否則就可以正常的執(zhí)行,并讓信號(hào)總量-1
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[self.person personA];
//發(fā)送一個(gè)信號(hào)镰烧,自然會(huì)讓信號(hào)總量加1拢军,
dispatch_semaphore_signal(self.semaphore);
});
}
- (void)timeActionB{
// 線程A
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[self.person personB];
dispatch_semaphore_signal(self.semaphore);
});
}
- (void)timeActionC{
// 線程A
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[self.person personC];
dispatch_semaphore_signal(self.semaphore);
});
}
Person類的實(shí)現(xiàn)。
-(void)personA{
self.num--;
NSLog(@"A票通道 剩余總票:%ld",(long)self.num);}
-(void)personB{
self.num--;
NSLog(@"B票通道 剩余總票:%ld",(long)self.num);
}
-(void)personC{
self.num--;
NSLog(@"C票通道 剩余總票:%ld",(long)self.num);
}
一:GCD分組實(shí)現(xiàn)線程同步
- (void)viewDidLoad {
[super viewDidLoad];
// 實(shí)例類person
self.person = [[Person alloc] init];
self.person.num = 100;
//創(chuàng)建隊(duì)列組隊(duì)
self.group = dispatch_group_create();
//模擬三條不同的網(wǎng)絡(luò)去搶票
[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(timeActionA) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timeActionB) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(timeActionC) userInfo:nil repeats:YES];
}
- (void)timeActionA{
//進(jìn)入組
dispatch_group_enter(self.group);
//線程放進(jìn)隊(duì)列組
dispatch_group_async(self.group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.person personA];
//離開組
dispatch_group_leave(self.group);
});
}
- (void)timeActionB{
//進(jìn)入組
dispatch_group_enter(self.group);
dispatch_group_async(self.group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.person personB];
dispatch_group_leave(self.group);
});
}
- (void)timeActionC{
//進(jìn)入組
dispatch_group_enter(self.group);
dispatch_group_async(self.group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.person personC];
dispatch_group_leave(self.group);
});
}