• 沒有找到結果。

Java虛擬機的簡介

三、 Java 多媒體系統動態分析

3.6 Java Thread

3.6.7 Java虛擬機的簡介

Java虛擬機(JVM)提供multithread的功能,同時使用監視器(monitor)處理 同步的問題。其中最特別的thread為垃圾收集thread,其優先權最低,當有thread 不再需要執行時或是記憶體空間不足時,垃圾收集thread就自動啟動,以整合零 碎自由的記憶空間(fragment),以形成一個較大的記憶區塊,為往後系統需要 時做準備。

Java虛擬機定義了不同thread優先權,優先權高表示它將獲得多一些CPU時 間;低優先權thread只有當所有高優先權thread被終止後才能取得CPU控制時 間。但並不保證高優先權的thread一定會優先處理。

對於任何Java thread,Java虛擬機都必須同時支援:物件的鎖定和thread 等待、傳遞通告。物件的鎖定保證thread共享資料時不會互相影響,thread等待、

傳遞通告能幫助thread合作互相處理一些共同物件。

Java虛擬機規格明確記載thread必須執行以下兩個動作:

1.從主記憶體複製變數值到它的工作記憶體。

2.從它的工作記憶體寫入值到主記憶體。

Java的監視器支援thread兩種功能:不會互相影響與合作

不會互相影響,是經由在Java虛擬機獨立地將物件鎖定,才能夠使多個 thread互相分享資料。

合作,則是經由Java虛擬機使得thread進入封鎖狀態,以及等待類別物件 所傳遞的通告,賦予thread相互合作的能力,例如從一個緩衝區讀取資料,而有 另外thread執行寫入資料。以上根據[8]。

第四章 Thread 試驗

4.1 Thread封鎖與時間之試驗

在 3.3.2.1 節「處理影像資料」,相信讀者都會發現到,為什麼要刻意呼叫 sleep( )或是 wait( )函式,並且設置時間限制,使得呼叫這些函式的 thread 能在 一定的時間內進入封鎖狀態,或是為什麼一定要設置為此秒數呢?難道設置為其 它秒數就不行嗎?以下,本研究會做一些試驗,來說明麼要做如此的設置。

(1) PustThread(V)

PushThread (V)進入執行狀態後,會呼叫sleep(10)函式,封鎖此thread0.01 秒,當它再度進入執行狀態時,會呼叫yield( ),以達到和其它thread公平的排程,

以避免新的影像資料覆蓋到舊的影像資料。意謂著隔0.01秒後,此thread有機會 取得執行權,並且向camera存取影像資料。本實驗重新設置新的秒數(豪秒)如下 表格4-1:

表格4-1 thread Sleep試驗

豪秒 0 1 5 10 15 20 25 30 40 50 60 70 CPU% 74 13 16 14 10 15 7 11 8 11 11 22

由表格4-1的數據,可得知休眠期間設為0秒時,很明顯地CPU的負荷比其它 秒數據高了許多,換句話說若使此thread修眠的時間期間太短會加重CPU的負 荷,如圖4-1和圖4-2。但人類的眼睛對於動態視覺的連續性為每秒30~20張照片,

約為33ms~50ms,因此並沒有必要將此試驗中的秒數設置為0,如此做只會加重 CPU沒必要的負荷。並且若抓取照片的時間點相距太近則會抓取幾乎相同的照 片,而負責儲存擷取資料的暫存器也可能因空間不足而丟棄之前所儲存的資料,

因此必須設置適當的休眠時間,由此可知設置sleep()函式對整體系統而言是必 要的。

在此試驗中,使得此thread修眠的時間期間設為50ms秒以後,會發現圖片 會非常不連續,因此不可以將秒數設為50ms以後。由上可得適當的知休眠期間 為0~50(豪秒)。但經由觀察可發現設置休眠時間約在10ms時,播放影像的流暢度 是最好的。

圖 4-1 sleep(0),CPU 之使用率

圖 4-2 sleep(10),CPU 之使用率

(2)VFWTransferDatathread(V)

原先的預設為VFWTransferDatathread(V).wait(250),當無資料可以讀出 時,此thread會進入封鎖狀態0.25秒,本實驗重新設置新的秒數(豪秒)如下: 0、

5、10、70、800,對於CPU的負荷或是影像播放都是沒有任何影響,因為此thread 的可執行條件成立時,會收到解除封鎖的通告,此與時間是沒有任何關係的,但 希望此thread能在0.25內能重新回到待命狀態,或許當它在排隊取得執行權時已 有媒體資料進入暫存器,就不必再等待解除封鎖的通告。

RawBufferStreamThread(A/V)與VFWTransferDatathread(V)的原理是相

同的,因此試驗的結果也會相同。其中wait( )與wait(0)函式所執行的功能是相 同的。

4.2 Thread 執行次序和時間之量測

此小節,為探討本系統處理影像資料相關thread 執行的順序,當一 thread 開始執行資料存取的程式碼時,在此試驗我們將會抓取此 thread 開始執行的時 間點。在稍後的說明中,thread(0)表示為 VFWRequestThread(V);thread(1) 表 示 為 PushThread(V) ; thread(2) 表 示 為 VFWTransferDataThread(V) ; thread(3) 表 示 為 SourceThread(V) ; thread(4) 表 示 為 RawBufferStreamThread(V)。

由 3.3.2.1 節,可得知每一個thread 要對暫存器執行資料存取的程式碼前,

都必須要檢查暫存器的狀態,由圖 4-3 中,bQ1、bQ2 和 bQ3(暫存器)都有各自 專屬的thread 執行資料傳遞,當檢查暫存器的狀態為無法執行時,thread 就會 被它所檢查的暫存器鎖住,而無法執行。

由於在此是取得「thread 開始執行資料存取的程式碼」,其代表所取得為 thread 開始執行的時間點,若為 thread(1)表示已睡醒且執行過 yield( )函式,或 為thread(2)、(3)、(4)表示已通過第一個暫存器的狀態檢查,並且已開始執行資 料存取的程式碼,但由圖 4-3 中,thread(1)、(2)和(3)必須檢查第 2 個暫存器 的狀態,有可能被暫存器管理,而進入封鎖狀態,在圖 4-4 中我們會驗證第三章 的理論。

4.2.1 暫存器之儲存列

Open camera

bQ1 bQ2 bQ3

(0)

(1) (2) (3) (4)

Send out Open

camera

bQ1 bQ2 bQ3

(0)

(4): RawBufferStreamThread(V)

圖 4-3 暫存器內容 VFWTransferDataThread(V);thread(3)表示為 SourceThread(V);thread(4) 表示為RawBufferStreamThread(V)。

14

(0)VFWRequestThread(V) 1

1187 (millisecond)

1186033763375 1186033764562

1186033763390

1st loop 1186033764437

1186033764453

2st loop 1266 (millisecond) 3st loop 219 (millisecond)

4st loop 312 (millisecond)

(1)PushThread(V)

(2)VFWTransferDataThread(V) (3)SourceThread(V)

(4) RawBufferStreamThread(V)

1186033764468

5st loop 313 (millisecond)

(a)

1186033764656 1186033764703 1186033764765 1186033764578

1186033764781 1186033764828

(b)

圖 4-4 順序和時間量測(a)(b)

圖 4-4 中,縱軸表格中的號碼表示為thread(0)~(4)的執行順序,橫軸表示 此thread 的起始時間點,在此只標出部分觀察點,實際的部分數據請參考附錄 一。

此小節主要分為四部分: (1)Thread 執行次序,說明 thread 能依據 3.3.2 節的設計概念依序執行;(2)處理媒體資料的時間;(3)照片傳送時間點與bQ3 不足時的應變機制;(4)鎖住thread3 的時間試驗。

(1)Thread 執行次序

由 4.2 節可以得知處理影像資料的thread,進入待命狀態的順序為

thread(1)、(2)、(3)、(4)。由圖 5-4(a)中,NO.2、3 為 thread(1)執行兩次,

表示此時還未有其它thread 進入待命狀態。接下來若 thread (2)、(3)進入待命 狀態,thread (1)則必須讓出執行權,thread (3)若取得執行權就會被 bQ2 鎖住,

因此,此時能執行的唯有thread(2),thread (3)必須要等 thread (2)執行完後 才能執行。請參考表格 4-2 中NO.2~4。

NO.5 為 thread(3)執行,由 4.4 節可知 thread(3)完成執行資料寫入 bQ3 時,將被drainSync 物件鎖住,或 bQ3 物件不允許寫入而被 bQ3 物件鎖住,除 非thread(4)有起來執行,否則 thread(3)不可能解除封鎖。NO.9 為 thread(2) 自bQ1 取出資料欲存入 bQ2 中,由表格 4-2 可知 bQ2 不允許寫入資料,因此 thread(2)被 bQ2 物件鎖住,除非 thread(3)有執行否則無法解除封鎖。請參考 表格 4-2 中NO.5~9。

由NO.5 和 9,可知 thread(2)和 thread(3)已進入封鎖狀態,此時若 thread(4) 還未進入待命狀態,就唯有thread(1)可執行。當 thread(4)進入待命狀態時,

thread(1)若欲執行會因 yield()函式而放棄執行權再次進入待命狀態,thread(2) 和thread(3)已知為封鎖狀態,因此,NO.9 為 thread(4)執行的開始時間點,

thread(4)接著會解開 drainSync 物件或 bQ3 物件對 thread(3)的鎖定。請參考表 格 4-2 中NO.10~14。

NO.15 也唯有 thread(3)能執行,因 thread(2)在封鎖狀態並且 thread(1) 若欲執行會因yield()函式而放棄執行權再次進入待命狀態,只有 thread(3)能執 行,並且解開bQ2 物件對 thread(2)的鎖定。

個Loop 表示一張照片自抓取、壓縮至封裝 RTP 封包並開始自 Socket 發送所花 費的時間。表格 4-3 中為可以發現前 2 次所花費的時間特別多,這是因為main thread 此時還未執行完成,直到 main thread 呼叫 thread(4)的 start()函式之 前,thread(1)、(2)和(3)已經先在待命狀態,自然隨時可以先行取得執行權。

我們也可以發現每一個Loop 彼此間所花費的時間是有重複的,以圖 4-4 中 NO.2~13 為例,NO.6 為 thread(3)執行,當 thread(3)執行結束理論上要執行 thread(4),但由於前一段說明的理由,以及 Java thread 同步機制的特性,勢必 會為下一次要處理的資料先做處理。經由統計 13 張照片處理的時間(表格 4-3),

可以發現後期的第 3~13 張所花費的時間是比較少的,其平均值約為 241.8 (millisecond),因此也可以得知每個 thread 彼此間切換的時間花費是很少的。

因此可以得知要依序以thread(1)、(2)、(3)、(4)執行,基於上面敘述的 理由,在multithread 是很難做到的,但也因 thread 彼此的牽制使得 thread 之 間能相互合作。

表格 4-3 處理資料時間表

Loop 1 2 3 4 5 6 7 Time(millisecond) 1187 1126 219 313 313 344 328 Loop 8 9 10 11 12 13

Time(millisecond) 297 203 141 157 157 188 Average(3~13) 241.8 (millisecond)

(3)照片傳送時間點和bQ3不足時的應變機制

由3.3.2節可知當thread(3)執行時,最後一定會將媒體資料的尾端放入 bQ3,而此時會執行drainSync.wait(3000)函式,thread(3)會被drainSync物件 鎖住3秒,3秒後會自動解開封鎖。除非thread(4)將bQ3中的資料送到Socket發 送至網際網路,當thread(4)送出的封包為媒體資料的尾端就會執行drainSync.

notifyAll( )函式,提早解開drainSync物件對thread(3)的封鎖。由圖4-4中,NO.5

和NO.15之間差了328(millisecond)並未超過3秒,因此我們可以判定,NO.13 和NO.14必定將一張照片的所有封包發送自網際網路。

但thread(4)執行封包發送時,不一定會連續將bQ3內的封包送完,也可能分 為數次,實際數據請參考附件二,紫色方框內可以觀察到thread(4)將bQ3內最 後一個封包送出之前有發生其它thread起來執行的情況。會發生此情形是因為網 路發生壅塞的情形或是作業系統將執行權交給其它thread。

在此我們並不知道thread(3)壓縮後,會產生多少資料區塊逐一放入bQ3 中,因此bQ3很有可能會有空間不夠的問題,由附件二我們觀察到thread(4)執 行了6次,其表示當thread(3)無法將壓縮後的資料放入bQ3時,bQ3會鎖住 thread(3),直到thread(4)將資料自bQ3取出時,就會解除bQ3對thread(3)的封 鎖,thread(3)則會把壓縮完成的資料放入bQ3,完成一張照片的壓縮,thread(4) 會再執行送出bQ3內的資料至Socket,因此附件二中會有顯示thread(4)執行了6 次。

(4)鎖住thread3的時間試驗

由「(3)照片傳送時間點和bQ3不足時的應變機制」可知利用drainSync.

wait(3000)函式可以保證thread4必定會將bQ3內所有關於一張照片的封包全部

45 中的NO.22~24此情形發生。

4.3 結論與相關探討 (1)Thread的數量

對於本章的第一節,本論文點出在此系統,處理影音資料總共會用到9個 thread,處理影像使用5個thread,處理音訊使用4個thread。讀者一定感到困惑,

為什麼一定要用到9個thread,一個或是3~4個thread不行嗎?或是,使用更多的 thread不也一樣可以嗎?

當只使用單一thread,在所有子系統的暫存器間,往返搬運媒體資料,所有 的執行順序都必須依序執行,以此系統為例,自camera抓取媒體資料,放入 parser,作資料壓縮,送入網際網路,這一連串的程序是相當冗長的。當程式執 行至將封包送入網際網路時,程式必須要回到最初的子系統物件,也就是自 camera抓取媒體資料,當程式要回到此程序時,必須要經過多層函式的呼叫,

才能回到此程序,因此就浪費了許多時間在做多層函式的呼叫,整個程式的效率 就會相當的差,相對的接收端做播放時就會有很大的延遲,因此本研究不使用單 一thread。

本研究是依子系統的各別功能,而由專屬的thread來執行任務,為了就是要 解決上述的問題,只要thread所要執行的是多個程序,就會發生上述效率變低的 問題。但若所使用的thread過多呢?此種情形,就會浪費作業系統的資源,每一

本研究是依子系統的各別功能,而由專屬的thread來執行任務,為了就是要 解決上述的問題,只要thread所要執行的是多個程序,就會發生上述效率變低的 問題。但若所使用的thread過多呢?此種情形,就會浪費作業系統的資源,每一

相關文件