函式呼叫時堆疊之應用

程序與執行緒

一個執行中的程式我們稱它為一個程序 (process), 支援多執行序的作業系統中 (Windows 95/NT), 每一個程序中可以有一個以上的執行緒 (thread), 每一個執行緒中 CPU 都獨立執行程式, 不互相干擾, (每一個執行緒就好像一個人一樣, 可以自行執行工作) 每一個執行緒擁有自己的堆疊 (stack) 來輔助其正確地執行函式。

輔助函式呼叫的堆疊

每一個 C 程式都由許多個函式組成, 當一個執行緒由一個函式執行到另一個函式時, 需要將回返點記錄下來, 如下圖, 以便函式二執行結束後返回函式一中繼續執行下去。

這些回返點每個執行緒會將之記錄在一個堆疊上,如下圖:

函式參數及區域變數

每一個函式內都可以宣告一些變數, 這些變數在記憶體內不能像全域性的變數一樣地使用固定的位置來存放, 因為:

  1. C 程式中容許函式遞迴地呼叫, 也就是函式可以呼叫自己, 因此一個函式可能在還沒有結束之前又再次地開始執行, 那麼這個新開始執行的函式內的變數和 舊的未執行完畢的函式內的變數究竟是相同的還是不同的?? 例如: 以上例而言, 如果每次呼叫 factorial() 函式時變數 n 的記憶體位址都是同一個的話, 會發生如下的狀況:

    上例中變數 n 的值不斷地被修改, 因此最後回傳時 n 之值為 2, 當然這個答案是錯的。 在 C 語言裡, 實際上每一次函式呼叫的變數 n 是完全不同的變數, 佔有不同的儲存位置, 所以執行的過程應該如下圖:

    這樣子性質的變數及函式引數如果製作在執行緒的堆疊上, 就可以達到上述每一次呼叫時變數獨立的要求:

    在函式返回時系統必須將堆疊上屬於那個函式的資料所有權釋放掉, 請注意系統沒那個閒功夫去把堆疊上不用的資料清除, 所以函式回返以後千萬不要再去存取函式內的變數了, 同時函式開始執行時不要以為區域變數裡的值會是 0。

  2. 多個執行緒可能同時執行同一個函式, 一個函式內的參數及區域變數對於不一樣的執行緒來說都是不一樣的, 還有在函式內呼叫其它函式時, 所記錄的回返點也必須分清楚, 否則兩個執行緒就互相影響了。 所以每一個執行緒必須將參數、 區域變數、 以及回返點都置於它自己專用的堆疊上。

區域變數應用的注意事項

  1. 由於在堆疊上配置資料, 陣列的大小必須有所限制, 一般情況下執行緒的堆疊可以由數 K bytes 到數十 K bytes, 如果你在區域變數宣告一個 char image[1024][1024]; 這個陣列需要 1M bytes 的空間, 就會使得程式在執行的時候出現錯誤。

    注意

  2. 一個函式只有在被執行的時候其參數及區域變數才是有效的, 此函式一結束 (執行到函式的最後一列或是 return 敘述) 所有的變數所佔用的記憶體空間都會被系統收回, 準備給其它的函式使用。

程式設計課程 首頁
by Pei-yih Ting
E-mail: pyting@cs.ntou.edu.tw