什麼是鎖?為什麼存在?
多個執行緒執行的時候,共享了同一塊資源,在訪問這塊資源的時候就稱為臨界資源。為了解決這個問題,我們可以為這塊資源加上一把鎖,只允許乙個執行緒訪問這塊資源。
那今天就講講互斥鎖,自旋鎖。
首先先看看不加鎖的情況下多執行緒共享訪問臨界資源會發生什麼.
**很簡單,開啟10個執行緒,各加上100000,理想結果應該是10 * 100000,好的,來試試吧
```c
#include
#include
#define thread_num 10
int count =0;
void
*proc
(void
*arg)
}int
main()
;for
(i =
0; i < thread_num; i++
)while(1
)return0;
}
執行結果
[guojunfeng@guojunfeng mutex]$ ./mutex
total 9
total 158333
total 317776
total 476812
total 634098
total 793269
total 943308
total 997398
total 997398
total 997398
total 997398
total 997398
很明顯結果997398跟理想狀態1000000少了一些,丟失的那些值去哪了呢?為什麼會導致這種現象,是誰在作怪?
可能很多同學會說count是臨界資源沒有加鎖造成的,那為什麼沒有加鎖達不到理想值呢?這塊臨界資源到底發生了什麼事?
因為count++翻譯成指令,反彙編看看,其實是有三個指令,讀 加 寫。
[guojunfeng@guojunfeng mutex]$ objdump -s -d mutex > count
//找到count++的位置
400642: 8b 05 00 0a 20 00 mov 0x200a00(%rip),%eax # 601048 <__tmc_end__>
400648: 83 c0 01 add $0x1,%eax
40064b: 89 05 f7 09 20 00 mov %eax,0x2009f7(%rip)
# 601048 <__tmc_end__>
大概意思是:
讀取儲存count到臨時變數eax
edx再自增+1
儲存edx到count
本來理想狀態是以下這樣互動達到正確的++
絕大多數的狀態是這樣的,執行緒1完成三個指令後切換執行緒2執行
執行緒1執行緒2
mov 0x200a00(%rip),%eax
add $0x1,%eax
mov %eax,0x2009f7(%rip)
mov 0x200a00(%rip),%eax
add $0x1,%eax
mov %eax,0x2009f7(%rip)
但有少數情況並不是上面這樣的,競爭資源比較大的時候,會變成以下狀態
執行緒1執行緒2
mov 0x200a00(%rip),%eax
mov 0x200a00(%rip),%eax
add $0x1,%eax
mov %eax,0x2009f7(%rip)
add $0x1,%eax
mov %eax,0x2009f7(%rip)
如果此時的count值是10,那執行緒1執行了第一條指令取值10至eax,切換執行緒2進來執行完成三條指令,此時eax是11賦值給了count暫存器。
再次切換回執行緒1,執行緒1的臨時變數eax還是10,再進行自增後11賦值給了count暫存器。
最終這倆個執行緒++後的值是11,並不是12。所以這就可以解釋上面**為什麼沒達到理想值了。
那我們要怎麼做才能讓執行緒1執行++的時候是不讓別的執行緒進來呢?答案就是執行階段加上一把鎖。
互斥鎖和自旋鎖:
#include
#include
#define thread_num 10
int count =0;
pthread_mutex_t mutex;
pthread_spinlock_t spinlock;
void
*proc
(void
*arg)
}int
main()
;pthread_mutex_init
(&mutex,
null);
pthread_spin_init
(&spinlock, pthread_process_shared)
;for
(i =
0; i < thread_num; i++
)while(1
)return0;
}
開啟互斥鎖**就其實加了4行,因為是演示,鎖的銷毀就沒處理,int pthread_mutex_destroy(pthread_mutexattr_t *attr);
定義了乙個mutex的互斥鎖,進行初始化,在進行count++的時候lock,執行完再unlock。
看下執行結果
[guojunfeng@guojunfeng mutex]$ ./mutex
total 10
total 158645
total 316088
total 475166
total 635056
total 795857
total 955740
total 1000000
total 1000000
total 1000000
total 1000000
其實開啟spinlock開關結果也是正確的。
加鎖的這期間是做了什麼事情呢?
那分別應用在什麼場景下?
mutex是對於處理時間比較長的,比較複雜的
spinlock對於時間較短,比較簡單的
以執行緒切換作為乙個標準,如果這個處理時間超過切換執行緒的代價,就採用mutex,相反採用spinlock。
為何需要建立執行緒
個人以為是為了提高cpu利用率。執行緒給作業系統帶來的建立維護和管理負擔要輕。因為與執行緒相關的資訊比較少,交情的負擔意味著執行緒的代價或開銷比較少。當處理器除乙個程序並啟用另乙個程序時,就要發生上下文切換。為了發生上下文切換,作業系統必須啟動和重新啟動每個程序所需的資訊。這就意味著必須儲存描述程序...
為何需要核函式
生存?還是毀滅?哈姆雷特 可分?還是不可分?支援向量機 之前一直在討論的線性分類器,器如其名 汗,這是什麼說法啊 只能對線性可分的樣本做處理。如果提供的樣本線性不可分,結果很簡單,線性分類器的求解程式會無限迴圈,永遠也解不出來。這必然使得它的適用範圍大大縮小,而它的很多優點我們實在不原意放棄,怎麼辦...
為何需要呼叫「super viewDidLoad」
super didreceivememorywarning void viewdidload 在上面的 中,什麼需要呼叫父類相應的方法呢?以viewdidload為例,父類 super 中的 viewdidload 會幫助你做一些初始化的工作,比如 a是父類,b繼承a,b 在viewdidload ...