在計算機中存在進程和線程的概念,其中進程是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位,線程是進程的一個執(zhí)行單元,是比進程還要小的獨立運行的基本單位。在一個程序中至少有一個進程,一個進程至少有一個線程。進程是資源分配最小單位,線程是程序執(zhí)行的最小單位。
計算機在執(zhí)行程序時,會為程序創(chuàng)建相應的進程,進行資源分配時,是以進程為單位進行相應的分配。每個進程都有相應的線程,在執(zhí)行程序時,實際上是執(zhí)行相應的一系列線程,過程如下圖所示。
在SystemVerilog中,雖然IEEE中也使用了process和thread,但是在實際手冊解釋的過程中,兩個概念基本上處于互用的狀態(tài),所以本文統(tǒng)一使用線程進行描述說明SystemVerilog中線程常用的精細化控制方法。
在SystemVerilog中,線程的創(chuàng)建主要有以下幾種方式:
?每一個initial結構都會創(chuàng)建一個對應的線程;
?每一個final結構都會創(chuàng)建一個對應的線程(關于final用法參考《SystemVerilog中的final是怎么結束的》);
?每一個always、always_comb、always_latch和always_ff結構都會創(chuàng)建對應的線程;
?fork-join(join_any/join_none)結構中每條并行執(zhí)行的語句塊;
?每一個動態(tài)線程,一般并行執(zhí)行的線程并且不會阻塞其他線程或者task中其他語句執(zhí)行的線程;
?每一個連續(xù)賦值語句;
在SystemVerilog中可以通過process來實現(xiàn)對于上述線程的控制,而這個process其實是SystemVerilog中的一個內(nèi)建類,通過該類聲明的句柄可以指向特定的線程,從而可以通過該句柄實現(xiàn)對于指向線程的訪問控制。process類在SystemVerilog中的定義如下:
雖然process是一個類,但是這哥們比較特殊,不能被拓展派生,也就是說process不會有子類的,并且該類在創(chuàng)建對象時,是不能使用new函數(shù)的,process類型句柄指向?qū)ο笫峭ㄟ^process::self()完成的,因此如果用戶需要通過process句柄指向?qū)木€程時需要在對應的線程中調(diào)用process::self()實現(xiàn)。在process中經(jīng)常用來實現(xiàn)對于線程控制的方法主要如下:
?self()返回指向當前線程的句柄;
?status()返回當前句柄指向線程的狀態(tài)(包含的狀態(tài)有:FINISHED、RUNNING、WAITING、SUSPEND和KILLED等狀態(tài));
?kill()終止當前句柄指向的線程及其開啟的所有子線程;
?await()等待調(diào)用其的句柄指向的線程執(zhí)行完成,注意不能在調(diào)用其的句柄指向的線程中使用該方法,只能在別的線程中調(diào)用該方法用以阻塞調(diào)用該方法的句柄指向的線程;
?suspend()掛起當前句柄指向線程;
?resume()恢復被掛起的線程;
?srandom()設置線程的隨機種子;
上述方法中,kill()、await()、suspend()、resume()只能用于initial、always和fork結構啟動的線程。下面將針對process中這些方法的使用進行示例說明。
【示例】
【仿真結果】
示例中,首先聲明了兩個句柄p1和p2,在兩個initial結構中,p1和p2通過調(diào)用“process::self()”實現(xiàn)p1和p2分別指向其所在的initial結構開啟的線程。
在第一個initial結構中“@0”時刻第一個$display中通過p1.status()方法獲取了當前線程的狀態(tài)(log中顯示為RUNNING),然后等待10個時間單位后,再次調(diào)用$display(),在其中調(diào)用p1.status()方法獲取了當前線程時刻“@10”的狀態(tài)(log中顯示為RUNNING),再經(jīng)過100個時間單位,在時刻@110再次在$display()中調(diào)用p1.status()方法獲取了當前線程的執(zhí)行狀態(tài)(log中顯示為RUNNING),該語句執(zhí)行完后第一個initial結構開啟的線程執(zhí)行完畢。
第二個initial結構中,“@0”時刻第一個$display中通過p2.status()方法獲取了當前線程的狀態(tài)(log中顯示為RUNNING),然后等待10個時間單位后,再次調(diào)用$display(),在其中調(diào)用p2.status()方法獲取了當前線程時刻“@10”的狀態(tài)(log中顯示為RUNNING),然后通過p1調(diào)用await()方法,p1.await()后的語句將處于等待p1指向線程執(zhí)行完畢,其后的語句此時處于阻塞的狀態(tài),當p1指向的線程(也就是第一個initial結構)在時刻“@110”執(zhí)行完畢,p1.await()不再阻塞其后語句的執(zhí)行,其后的語句繼續(xù)執(zhí)行,此時調(diào)用p1.status()顯示的值為p1當前的狀態(tài)(log中顯示此時p1狀態(tài)位FINISHED)。在等待100個時間單位,在時刻“@210”調(diào)用p2.status()時,p2指向的線程還沒有執(zhí)行完畢,所以其顯示的狀態(tài)仍為RUNNING。上述兩個線程執(zhí)行的過程如下圖所示。
【示例】
【仿真結果】
示例中,聲明了三個process句柄p1、p2和p3.在initial結構中調(diào)用“process::self()”實現(xiàn)p1指向當前的initial結構開啟的線程,然后調(diào)用$display語句通過p1.status()獲取當前initial結構開啟線程的執(zhí)行狀態(tài)為RUNNING(該initial結構正在執(zhí)行中)。
fork-join_none結構中所有語句是并行執(zhí)行的,示例中的fork結構中一共有三個線程,
第一個線程通過調(diào)用“process::self()”實現(xiàn)p2指向自己,當該方法結束后,該線程的歷史使命也就結束了,這里需要注意p2并沒有指向fork。
第二個線程為一個begin-end結構,在begin-end中首先通過調(diào)用“process::self()”實現(xiàn)了p3指向該線程,然后調(diào)用$display中通過p3.status()獲取當前線程執(zhí)行狀態(tài)為RUNNING(該begin-end結構還在執(zhí)行中),在等待100個時間單位,通過p2.status()和p3.status()獲取當前時刻p2和p3指向線程的執(zhí)行狀態(tài),因為p2指向的線程在調(diào)用“process::self()”完后就執(zhí)行完了,所以p2.status()返回的狀態(tài)位FINISHED,p3.status()獲取的狀態(tài)值仍為RUNNING(其所指向begin-end結構還在執(zhí)行中),再等待100個時間單位,通過p2.status()和p3.status()獲取當前時刻p2和p3指向線程的執(zhí)行狀態(tài),因為此時fork-join_none中并行執(zhí)行的第三個線程通過p3調(diào)用了kill()方法,所以begin-end結構對應的線程被kill掉,因此此時企圖在等待100個時間單位再次獲取p2和p3執(zhí)行狀態(tài)的語句不會執(zhí)行。
第三個線程為等待190個時間單位后調(diào)用p3.kill(),實現(xiàn)了對于fork-join_none中第二個線程的kill操作。
fork-join_none結構后通過p1.status()獲取p1指向線程的執(zhí)行狀態(tài)為RUNNING(因為p1指向的initial結構正在執(zhí)行中);
在經(jīng)過10個時間單位,通過p2.status()和p3.status()獲取當前時刻p2和p3指向線程的執(zhí)行狀態(tài)分別為FINISHED(p2指向線程已經(jīng)執(zhí)行完畢)和WAITING(p3指向線程正在執(zhí)行其中#100,處于延遲阻塞等待狀態(tài));
通過p2.kill()企圖kill掉p2指向的線程,實際上此時p2指向的線程已經(jīng)執(zhí)行完畢,所以并不會影響p2指向線程的狀態(tài),所以此時在p2.kill()后通過p2.status()和p3.status()獲取當前時刻p2和p3指向線程的執(zhí)行狀態(tài)仍為FINISHED(p2指向線程已經(jīng)執(zhí)行完畢)和WAITING(p3指向線程還在執(zhí)行其中#100,處于延遲阻塞等待狀態(tài));
在經(jīng)過210個時間單位,通過p1.status()、p2.status()和p3.status()獲取當前時刻p1、p2和p3指向線程的執(zhí)行狀態(tài)為RUNNING(p1指向的initial結構正在執(zhí)行中)、FINISHED(p2指向線程已經(jīng)執(zhí)行完畢)和KILLED(p3指向的線程執(zhí)行完之前,在fork-join_none結構中等待190個時間單位時已經(jīng)被kill掉了,所以此時狀態(tài)位KILLED);上述線程執(zhí)行過程如下圖所示。
【示例】
【仿真結果】
示例中,p通過“process::self()”指向了當前的線程,通過$display顯示了p.status()為RUNNING,等待100個時間單位,企圖通過p.status()顯示p的狀態(tài),但是在這100個時間單位等待到其中的20個時間單位時,另外一個initial結構中仿真開始等待的20個時間單位后調(diào)用了p.suspend(),即此時將p指向的線程掛起,所以此時p指向的線程這時處于掛起等待狀態(tài),$display顯示了p.status()為SUSPEND,在再等待30個時間單位,調(diào)用p.resume()將之前掛起的p指向的線程返回,因為當前線程并未阻塞,所以當前線程繼續(xù)執(zhí)行,$display顯示了p.status()為WAITING,當前initial執(zhí)行完后,p指向的線程再次開始繼續(xù)之前暫停的執(zhí)行。
再等待80個時間單位(之前100個時間單位計時20個時間單位后還剩下80個時間單位未計時)調(diào)用$display顯示了p.status()為RUNNING,再等待100個時間單位后調(diào)用$display顯示了p.status()仍為RUNNING。上述線程執(zhí)行過程如下圖所示。
通過示例可以看到,await是用來等待一個線程執(zhí)行完成后返回的,而suspend則用來將一個線程手動掛起,其解除必須通過resume()來完成,并不一定要等到線程執(zhí)行完畢。
上述通過示例展示了process中常用方法的使用,其實在UVM中對于線程的控制大多都是通過process完成的,如下例中run_phase的執(zhí)行。
當我們執(zhí)行run_test時,實際上在run_test這個task中聲明了一個process句柄phase_runner_proc,這個句柄在425行通過“process::self()”指向了當前fork-join_none結構中的一個線程,這個線程就是fork-join_none中的begin-end。當后續(xù)的m_run_phases()執(zhí)行完成后,wait等到了m_phase_all_done拉高,表明當前的run_phases執(zhí)行完畢,然后通過phase_runner_proc.kill()將fork-join_none中開啟的線程及其所有子線程都kill掉,相當于打掃戰(zhàn)場,從而通過process實現(xiàn)了對于fork-join_none中線程及其所有子線程的控制操作。
審核編輯:劉清
-
計算機
+關注
關注
19文章
7663瀏覽量
90825 -
Verilog
+關注
關注
29文章
1367瀏覽量
112297 -
UVM
+關注
關注
0文章
182瀏覽量
19552
原文標題:進程(線程)精細化控制中方法的使用
文章出處:【微信號:處芯積律,微信公眾號:處芯積律】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
[原創(chuàng)] 歐洲精細化工展覽會(ChemSpec Europe 2010)
2010年迪拜精細化工展
2010迪拜精細化工展/中東化工技術機械展
怎么才能讓無線站點實現(xiàn)精細化覆蓋?
實用精細化工辭典

精細化工常用原材料手冊

無線站點精細化覆蓋
基于UEMS的電力系統(tǒng)精細化穩(wěn)定控制系統(tǒng)
如何才能實現(xiàn)smt貼片車間的精細化管理
福斯特、光華科技、西隴科學上榜2020中國精細化工百強企業(yè)榜單
基于TransModeler軟件的精細化交通設計
進程(線程)精細化控制中方法的使用
綜合管廊精細化節(jié)能系統(tǒng)設計與實施

評論