三、 Java 多媒體系統動態分析
3.3 Thread之間的資料分享與溝通
3.3.2 Thread的設計原理與制衡
3.3.2.1 處理影像資料
此小節說明處理影像Thread 的設計原理與制衡機制。在圖 3-4 中,處理影
像資料的 threads 會執行各自的任務,所有箭頭的起始點和終點表示為各個 thread 所必須要處理的物件,以及物件內的暫存器,其中 bufferQ1 有 8 個 queue,bufferQ2 有 1 個 queue,前兩者的 queue 都為儲存一張照片的大小。
bufferQ3 有 5 個 queue,每個 queue 都為儲存一預設 RTP 封包的大小。
Thread0:VFW RequestThread(V) Thread1:PushThread (V)
Thread2:VFW TransferDataThread (V) Thread3:SourceThread(V)
Thread4:RawBufferStream Thread(V) Object Thread Path
RawBufferParser buffer1 bufferQ2
以下會針對每一個thread 的設計概念做說明,當有對 bufferQ1、bufferQ2 或bufferQ3 作處理時,都會啟動同步機制,此 3 個物件會宣告為 synchronized(請 參考 3.6.3~3.6.6 節)。
Thread0:負責管理 camera,如開啟 camera。除非有其它 thread 要求它改變狀 態,否則當它取得執行權時,並不會做任何程序就會再度回到待命狀態。
Thread1:負責從 camera 取得影像資料,並存入 bufferQ1。
由於擷取影像資料的時間點不能太近,並且希望盡量達到公平的排程,因此 使用sleep(time)函式,使得 Thread1 休眠數豪秒後再起來執行,並且使用 yield() 函式,若Thread1 此次已執行過,下一次的執行機會能讓給其它的 thread,以 上流程如圖 3-5。
接著必須檢查bufferQ1可否放入資料,當無法放入資料時,表示已有8張照 片未處理,因此會清除在bufferQ1內最早放入的照片。接著將擷取的影像資料放 入一暫存器buffer,再將buffer內的資料放入bufferQ1,此時會執行bufferQ1.
notifyAll()函式,此函式主要為通知Thread2隨時可取走資料,接著將記錄buffer 資料量的參數設為0(接下說明相同的程序時都稱之為「清空暫存器」),為下一 次的影像資料做準備。以上流程如圖3-5。
圖3-5 PushThread(V)
Thread2:負責將bufferQ1內的資料搬運至bufferQ2。
首先必須要確定兩件事:1.Thread2可以取得影像資料,因此會檢查bufferQ1 可否讀出資料,若無法取得影像資料Thread2就會在此等待影像資料。當確定可 以取得影像資料時,必須確定另一件事:2.Thread2可否將資料放入bufferQ2,因 此會檢查bufferQ2可否放入資料,當判定無法放入資料時,Thread2會在此等待 Thread3將bufferQ2內的資料取走。
當上述兩件事都成立時,才會開始執行真正資料搬運的動作。首先,會先宣 告一暫存器buffer,將bufferQ1內的資料放入buffer,並且清空bufferQ1所存放
此資料的queue。接著再將buffer內的資料放入bufferQ2,並執行bufferQ2.
notifyAll()函式,通知Thread3隨時可取走資料。以上流程如圖3-6。
圖3-6 VFWTransferDataThread(V)
Thread3:負責自bufferQ2讀出資料後,對取出的資料做壓縮的處理,同時切割 為數個封包,並且依序放入bufferQ3。
首先必須確定Thread3能否取得影像資料,因此檢查bufferQ2可否讀出資 料,當無法自bufferQ2讀出資料時,Thread3會等待Thread2將影像資料放入 bufferQ2。
當Thread3可以自bufferQ2讀取資料時,宣告一暫存器buffer1,將bufferQ2 的資料放入buffer1,接著清空bufferQ2並通知Thread2隨時可放入新的影像資 料。將資料暫時存入buffer1是為了要對資料壓縮的處理做準備,當buffer1的資 料壓縮好並切割為封包大小後放入buffer1`,接著buffer1`所存的封包必須要逐 一放入bufferQ3。
因此必須檢查bufferQ3可否放入資料,當無法放入資料時,Thread3會等待 Thread4取出bufferQ3內的封包。當Thread3可以將封包放入bufferQ3時,會宣 告一暫存器buffer,接著將buffer1`內的封包放入buffer,再將buffer內的封包逐
一放入bufferQ3,並且告知Thread4隨時可將封包取出。
最後Thread3會檢查自buffer送出的封包是不是為最後一個封包,若是最後 一個封包,則Thread3會等待一段時間,此做法是希望再壓縮下一張照片前,
Thread4已將此次照片相關的封包都發送自網際網路,當Thread4發送出最後一 個封包時就會通知Thread3可以壓縮下一張照片。以上流程如圖3-7。
圖3-7 SourceThread(V)
Thread4:負責將bufferQ3內的封包一一讀出,建構為RTP封包,並交給Socket 發送。
首先Thread4必須確定是否有封包要發送,因此必須檢查bufferQ3可否讀出 資料,若判定無法讀出資料,Thread4則會等待Thread3將封包放入bufferQ3。
當Thread4可以自bufferQ3讀出封包時,宣告一暫存器buffer,接將bufferQ3內 的封包放入buffer,接著檢查buffer內所存的是不是為最後一個封包,若是最後 一個封包,Thread4會通知Thread3可以壓縮下一張照片。最後清空bufferQ3內 存放此次封包的queue。以上流程如圖3-8。
圖3-8 RawBufferStreamThread(V) (2) Thread制衡機制
由上述各個thread 的執行概念,下圖 3-9 為暫存器可能管理的 thread 之整 理。bufferQ1 可能管理 VFWTransferDataThread(V),藉由封鎖時間的結束,
VFWTransferDataThread(V) 可 自 動 解 開 bufferQ1 的 封 鎖 , 或 是 由 PushThread(V) 將 資 料 放 入 bufferQ1 時 , 通 知 bufferQ1 解 除 VFWTransferDataThread(V) 的 封 鎖 , VFWTransferDataThread(V) 隨 時 可 自 bufferQ1 讀取資料。
bufferQ2 可能管理 VFWTransferDataThread(V)或 SourceThead(V),也意 味著此兩個thread 同時是藉由 bufferQ2 來溝通。當 VFWTransferDataThread(V) 無法將資料放入bufferQ2 時,此 thread 會被 bufferQ2 封鎖,直到 SourceThead(V) 通 知 bufferQ2 解 除 對 VFWTransferDataThread(V) 的 封 鎖 時 , VFWTransferDataThread(V)就會得知可以將資料放入 bufferQ2 的通知。反之 亦然。
bufferQ3 可能管理 SourceThead(V)或 RawBufferStreamThread(V) ,也意 味著此兩個 thread 同時是藉由 bufferQ3 來溝通。當 SourceThead(V)無法將資 料 放 入 bufferQ3 時 , 此 thread 會 被 bufferQ3 封 鎖 , 直 到
RawBufferStreamThread(V)通知 bufferQ3 解除對 SourceThead(V)的封鎖時,
SourceThead(V)就會得知可以將資料放入 bufferQ2 的通知。
當RawBufferStreamThread(V)無法自 bufferQ3 取得封包時,會被 bufferQ3 鎖住,此thread 可藉由封鎖時間結束而自動結束封鎖,或是 SourceThead(V) 將封包放入bufferQ3 時,會通知 bufferQ3 解除對 RawBufferStreamThread(V) 的封鎖。
圖 3-9 buffer manage(V)
由Thread 的設計原理可知 SourceThead(V)和 RawBufferStreamThread(V) 之間還外加有一控制機制。當SourceThead(V)壓縮並送出最後一個封包時,必 須進入封鎖狀態,等待RawBufferStreamThread(V)將 bufferQ3 內的最後一個 封包發送出去時,SourceThead(V)就會解開封鎖繼續壓縮下一張照片。如圖 3-9 的右下方。
(3)暫存器狀態判斷機制
由前,對於Thread間的制衡機制的介紹,可知必須要有相關機制加以判斷 暫存器是否可以被放入或是讀取資料。當要判斷可否自暫存器讀出資料時,呼叫 canRead( )函式,此函式會檢查記錄暫存器資料量的參數是否大於零,當大於零 時,會回傳一true的布林值,表示此暫存器內存有資料。當要判斷可否放入資料
時,呼叫canWrite( )函式,此函式會檢查記錄暫存器剩餘空間的參數值是否為
RawBufferParser buffer1 bufferQ2 Thread2:DirectSound PushThread (A) Thread3:SourceThread(A)
Thread4:RawBufferStream Thread(A)
Object buffer
Thread Path
1
2