標籤:errno java linux threadlocal 線程變數
Linux裡的errno
在Linux下執行系統調用時,一般會有一個傳回值表示成功或失敗,但是這個值只說明了成功或失敗,卻沒有說明是如何成功或失敗的。
errno就是為瞭解決這個問題的,系統調用會把錯誤號碼設定為errno,我們通過錯誤號碼就能知道失敗的原因。還可以使用strerror列印出這個錯誤號碼對應的字串說明。老版本的Linux需要加上extern int errno,現在直接引入<errno.h>就行了.
errno樣本:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/6F/6A/wKioL1WbuPjQ9_gzAAHrJFspGzI545.jpg" title="選區_002.png" alt="wKioL1WbuPjQ9_gzAAHrJFspGzI545.jpg" />
現在的問題來了。假如我有兩個線程,代碼如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/6F/6D/wKiom1Wbt2CSHc8DAAC4FjSCW0c854.jpg" title="選區_011.png" alt="wKiom1Wbt2CSHc8DAAC4FjSCW0c854.jpg" />
errno是一個全域變數,那麼假如執行順序為 1-1,2-1,1-2,2-2,線程1列印出的errno就是線程2的,這就是errno的問題,線程不安全。
但是測試很多次,結果都是正確的。雖然你用這個errno是當作一個全域變數的,但是實際上是個宏。用gcc -E將原始碼的宏展開,可以看到,errno被替換成了一個函數。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/6F/6A/wKioL1WbuZuyhJVTAAJJJiKqJHo234.jpg" title="選區_003.png" alt="wKioL1WbuZuyhJVTAAJJJiKqJHo234.jpg" />
使用man errno查看對errno的解釋,可以看到下面一句話:
errno is defined by the ISO C standard to be a modifiable lvalue of
type int, and must not be explicitly declared; errno may be a macro.
errno is thread-local; setting it in one thread does not affect its
value in any other thread.
所以errno並不是一個全域變數,而是一個thread-local,每個線程都有一個。我們可以自己實現一個errno。
自己寫一個errno
僅僅示範一下errno的基本原理,使用一個map存放各個線程的errno,而這個map的key就是threadId。系統調用執行完畢後,會將錯誤碼寫入此線程對應的errno中。代碼中的系統調用是一個假系統調用,some_system_call()。
實際開發中,對於開發人員,他實際上是看不到set_errno(),get_errno()這些函數的,他只需要取errno就行了。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/6F/6D/wKiom1Wbudzhz-3IAAUruAEgEOY812.jpg" title="選區_007.png" alt="wKiom1Wbudzhz-3IAAUruAEgEOY812.jpg" />
Java的ThreadLocal
Java的ThreadLocal和Linux的errno是一樣的,只不過errno對開發人員來說更簡單一點,而且只能取,當作一個變數就行了。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/6F/6A/wKioL1WbvwTCsMG7AAI8sT9dyJo690.jpg" title="選區_013.png" alt="wKioL1WbvwTCsMG7AAI8sT9dyJo690.jpg" />
只定義了一個ThreadLocal,但是各個線程裡的都不一樣。
自己實現一個ThreadLocal
其實ThreadLocal也和上面我自己實現的errno類似,用了一個Map,感興趣的可以去看一下jdk源碼,我寫了一個很簡陋的MyThreadLocal,Java的ThreadLocal的原理大致就是這樣的。直接將上面的代碼的ThreadLocal替換成MyThreadLocal就可以運行,當然這個MyThreadLocal太簡單,僅僅為了介紹原理。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/6F/6A/wKioL1WbwHKxdsl-AAJ3jZYOBEA724.jpg" title="選區_009.png" alt="wKioL1WbwHKxdsl-AAJ3jZYOBEA724.jpg" />
本文出自 “牛哥的部落格” 部落格,轉載請與作者聯絡!
從Linux的errno到Java的ThreadLocal