2014-04-04 15 views
7

這裏的代碼,IBM公司表示,一個片段是折返的:爲什麼這個代碼被認爲是可重用的,當OS中斷某個線程時究竟發生了什麼?

/* reentrant function (a better solution) */ 
char *strtoupper_r(char *in_str, char *out_str) 
{ 
    int index; 

    for (index = 0; in_str[index]; index++) 
    out_str[index] = toupper(in_str[index]); 

    out_str[index] = 0 

    return out_str; 
} 

對我來說,這個代碼是不可重入的,因爲循環計數器指數正在本地定義。如果操作系統在循環中斷這個線程,並且另一個線程調用這個函數,索引將會丟失。我錯過了什麼?爲什麼這段代碼被認爲是可重入的?

當操作系統中斷線程並在處理繼續時重新建立變量時,操作系統是否會將索引等局部變量的副本保存到線程堆棧中?

它似乎使這個功能重入索引必須作爲調用者提供的存儲接口的一部分。

+0

是的,堆棧變量是線程本地的,如果有中斷,將會被保存。 – clcto

+0

所以如果線程A調用這個函數並且在循環中被中斷,所以線程B可以調用相同的函數,那麼當線程A繼續時,所有的狀態信息線程A需要繼續,它的中斷將重新建立?發生這種情況是因爲當處理器中斷線程A時,它會將局部變量(如索引)保存到線程堆棧,然後在處理恢復時重新建立這些變量?因此從來沒有對函數和局部變量的爭用。 – brimaa

+0

本地變量'index'沒有「保存」到堆棧。它首先在棧上生存。 –

回答

6

不可重入,因爲循環計數器的索引正在本地定義。如果操作系統在循環中斷這個線程,並且另一個線程調用這個函數,索引將會丟失。我錯過了什麼?爲什麼這段代碼被認爲是可重入的?

當發生中斷時,CPU本身至少會保存當前的指令指針(可能是標誌寄存器和幾個段寄存器和堆棧寄存器,但也取決於CPU) (對於x86)根據特定內存地址處的函數指針表調用代碼。這些中斷處理程序可以保存(例如推送到堆棧)他們想使用的其他寄存器,然後在返回之前恢復它們。

每個線程都有自己的堆棧,所以這一切都掛在一起。

當操作系統中斷線程並在處理繼續時重新建立變量時,操作系統是否將局部變量(如索引)的副本保存到線程堆棧中?

常...要麼保存到堆棧,或某些CPU(如SPARCS)具有寄存器窗口 - 相同的CPU操作碼針對不同的寄存器而中斷處理程序運行,那麼上下文切換回寄存器中的程序是使用。


就這麼停止來自被重入,功能如一個變量函數體內是靜態的,或一些全局變量/緩衝器使用非棧數據的。

4

非靜態局部變量通常分配在堆棧或寄存器上。每個線程都有自己的堆棧和寄存器副本(或者至少操作系統通過保存和恢復內容來創建該錯覺)。

因此,非靜態局部變量是線程安全的,它們在發生上下文切換時不會「忘記」它們的值。

相關問題