線程基本操作 (6)線程安全
線程安全 (thread-safe)
單個線程的程序就是一條支流很簡單的單步運行.
多線程的程序,就會產生多條分支,并行執(zhí)行.
那么并行中,有時候不能相互干擾,有時候需要進行相互通信.
(要確保,不相互干擾的時候,他們之間的數(shù)據不公用. 相互通信的時候,能夠保證數(shù)據的同步)

不相互干擾:
創(chuàng)建的每個線程都有自己的棧地址空間,每個線程中的局部變量都是定義在線程棧中的(和函數(shù)有點類似).每個線程棧都是獨立的,不會相互干擾.
有一個問題,假設我定義了3個新的線程A,B,C.
三個新線程調用了同一個初始start函數(shù)(每個線程運行時候,都調用同一個函數(shù)),這個函數(shù)中有局部變量的定義,那么,每個線程在調用函數(shù)的時候,都會定義局部變量到自己的棧中.

可重入函數(shù):
(重入指的是,同一個函數(shù)被不同線程調用,前一個線程還沒有跳出該函數(shù),另一個線程又開始調用該函數(shù)了.)

可重入函數(shù)特點:
1,函數(shù)內操作的變量都是內部定義的局部變量.這些變量是在??臻g中的.當函數(shù)調用結束返回時,再由系統(tǒng)回收所占用的棧.局部變量的聲明周期只限于函數(shù)執(zhí)行期間.
2,函數(shù)的形參和返回值都是值類型,而不是引用類型(指針).
3,函數(shù)中調用的其他子函數(shù),也是可重入的.
4,如果函數(shù)內部有全局變量,且全局變量僅僅限于讀取,這樣也可認為是可重入.
在man手冊中,經??吹揭恍┖瘮?shù)有兩個版本,
一種是帶_r后綴的,一種沒有帶后綴.
那么帶后綴_r的意思,就是可重入版本了.


一次性初始化
(函數(shù)中,有一部分代碼只需要進行一次執(zhí)行,比如:初始化代碼)
如果多個線程都要執(zhí)行 init_routine(),
那么只能有一個函數(shù)會真真的執(zhí)行 init_routine() 其他函數(shù)都會進入阻塞狀態(tài).
// 例子:
編譯并運行:


線程特有數(shù)據
線程特有數(shù)據,也稱為線程私有數(shù)據,
就是為每個調用線程分別維護一份變量的副本(copy).
每個線程通過特有數(shù)據鍵(key)訪問時,
這個特有數(shù)據鍵就會獲得本線程綁定的變量副本.
這樣就可以避免成為多個線程間的共享數(shù)據.
c庫中,有很多函數(shù)都是非線程安全函數(shù).
線程特有數(shù)據的思想就為每一個調用線程,分配屬于線程的私有數(shù)據區(qū),
為每個線程分別維護一份變量的副本.
涉及到3個函數(shù):

線程局部存儲
通常情況下,進程中定義的全局變量是被其下所有線程共享的.
所有線程都可以訪問這些全局變量.
線程局部存儲和線程特有數(shù)據實現(xiàn)的功能基本類似.
都是讓各個線程擁有一份對變量的拷貝.
線程局部存儲的優(yōu)點是使用簡單.(相比線程特有數(shù)據要簡單).
線程局部存儲:
關鍵字 __thread, 在變量前加上__thread
線程局部存儲關鍵字是 __thread.
如果與static或extern連用,需要把 __thread 放到其后.
線程局部存儲的變量,可以在定義的時候賦初始值.
可以用&來獲取線程局部變量的地址.
線程局部存儲需要內核,pthreads,gcc編譯器的支持.