Udemy Course Multithreading, Concurrency & Performance 27
前面課程大多是針對單一個Resource的Lock介紹
接著介紹如果有N個可利用的Resources的狀況
— Semaphore Lock(實際使用上code稍微複雜,可參考下面範例解說)
就如停車場有8個車位,當有8台車將位置停滿
第9台車進來後就需要等待位置空出來
只要8個中任意個位置空出來(有一台車離開),這第9台車就可以補位進去
基本寫法如下:
甚至可以一次佔據複數的Resource
Semaphore Lock與其他Lock的不同之處要注意!
- Semaphore不具有Lock持有者概念
一般Lock(非Semaphore)使用下,A Thread鎖的只能由A Thread解鎖
Semaphore Lock則是B Thread可以去替A Thread鎖住的做解鎖
2.一堆Threads都能去做Semaphore.acquire()
3.單一個Thread甚至可以多次地Semaphore.acquire() x N
4.以上可得結論:二進位的Semaphore初始數量1 不等同reentrant
5.任何Thread都可release Semaphore,甚至沒在跑acquire的Thread都可以
接著往下
上述狀況在其他的Lock(非Semaphore)就不會發生
因為其他Lock只有鎖住的Thread可以release
綜上特性
所以Semaphore Lock其實最適合應用於副標題上Producer & Consumer狀況
以下圖示特殊執行方式來展示Semaphore Lock特性
同一時間右邊的consumer醒來往下執行
此時若Producer早一步進到下一輪則會
如上兩邊(Consumer 及 Producer)往復循環
但是當Consumer是跑比較快的話:
那麼大部分時間將是Consumer卡在full.acquire();
這狀況下因為沒有進到consumer(item),所以不太消耗CPU
但是當Consumer是跑比較慢的話:
那麼大部分時間將是Producer卡在empty.acquire();
並且等待Consumer執行完消耗item後釋放empty
整體運作大致如下:
並且只要小小修改後也支援複數個Producer,及複數個Consumer如下
1.首先更改被鎖的Resource為Queue(由Queue統一提供Resource item)
並訂定Queue的容許量為CAPACITY
為了保護Queue內的Resource item被太多Consumer & Producer消耗
另外建立一般的Lock(這邊簡單選用Reentrant Lock)
並改造Producer產生Resource item後交給Queue
上圖Producer直接產出Resource item後
提供給queue(執行queue.offer(item))
但是queue要保持一致性,所以queue.offer前後要lock起來(用普通lock即可)
而Consumer則如下
上圖Consumer確定拿到item後,亦即這個item就可以隨意消耗了
所以consumer(item)前後不用鎖
以上即改造完成!
同樣的概念也廣泛的應用在其他系統環節,例如TCP溝通等
確保有足夠的channel才能連線後做後續處理等