wordpress模板怎么添加菜單百度seo排名優(yōu)化教程
一、互斥鎖
1、CPU 運算過程
執(zhí)行完整個語句后,才會把數(shù)據(jù)寫入內存;如果執(zhí)行時被中斷,那么數(shù)據(jù)和上下文就會保存到線程的 TCB,但數(shù)據(jù)并不會被寫入內存。
1.1. 當 CPU 執(zhí)行完整個語句時

就用上圖舉個例子。?CPU 是如何執(zhí)行 a-- 這個句代碼的呢?
- 第一步,CPU 將內存中變量 a 的值(100)拷貝到運算器中。
- 第二步,在運算器中減一。
- 第三步,把新的值(99)拷回變量 a 里。
1.2. 當 CPU 還未執(zhí)行完這個語句,線程就被換出時

以上圖為例,CPU 剛執(zhí)行完減 1 操作,線程就被換出。遇到這種沒執(zhí)行完語句的情況,CPU 會把計算數(shù)據(jù)和該線程執(zhí)行的上下文(即該線程執(zhí)行到哪一行代碼)拷到該線程的 TCB 里;然后再為下一個線程服務。
2、解決方案——互斥鎖(mutex)
2.0. 什么是互斥問題
當多個線程并發(fā)執(zhí)行,并訪問同一個變量時,就會很容易發(fā)生變量的一致性問題。
如圖所示,假如我想讓變量?a 從 100 減到 0.
線程 1 在做完 a-- 操作后就被換出了:
?

線程 2 正常執(zhí)行完整個減 1 操作,并重復了很多次,直到減到 10,被換出,線程 1 進來了:


而此時 a 這個全局變量又從 10 變成 100 了。
所以,這個變量從始至終都只能被一個執(zhí)行流(線程)訪問。
2.1. 互斥鎖原理
下面這是線程申請鎖和釋放鎖的匯編代碼:
lock: // 申請鎖movb $0, %alxchgb %al, mutexif (al 寄存器的內容 > 0) return 0; // 申請鎖成功else 掛起等待;goto lock;unlock: // 釋放鎖movb $1, mutex喚醒等待 Mutex 的線程;return 0;

但是,如果當該線程執(zhí)行完第一句后就被換出了,那么該線程會把 al 寄存器的值和上下文保存到 TCB;然后再被換出;然后第二個線程再進來從上次的上下文開始接著執(zhí)行。所以,其實申請鎖的本質就是看哪個線程拿到 1,拿到 1 的那個線程就申請到鎖了。
2.2. 相關函數(shù)
2.2.1. pthread_mutex_t 類型
就是互斥鎖的類型。
2.2.2. pthread_mutex_lock 函數(shù)
這個函數(shù)用于申請互斥鎖。注意,這里只是把鎖加上而已,并不會創(chuàng)建鎖。?
2.2.3. pthread_mutex_unlock 函數(shù)
這個函數(shù)用于釋放鎖。注意,這里只是把鎖解開了,鎖還在。
2.2.4. 初始化全局的鎖
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
2.2.5. 初始化局部變量的鎖?
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);參數(shù):
mutex:要初始化的互斥鎖
attr:nullptr
?2.2.6. 銷毀互斥鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);
這個函數(shù)是直接讓鎖消失。
注意:
- 如果創(chuàng)建的鎖是用宏創(chuàng)建的,就不能掉這個函數(shù)。?
- 一定要在解開鎖了之后才能調用這個函數(shù)。
- 確保后面沒有線程用到這個鎖。
2.3. 臨界區(qū)
處于?pthread_mutex_lock 函數(shù)和?pthread_mutex_unlock 函數(shù)之間的區(qū)域就是臨界區(qū)。
2.4. 臨界資源
多線程執(zhí)行流共享的資源就叫做臨界資源。不過,臨界資源都是每次只能讓一個一個線程訪問的。但是當線程申請鎖時,那么鎖也是共享資源;所以申請鎖和釋放鎖本來就被匯編語言設計成原子性的(即只用一句匯編實現(xiàn))。
二、死鎖
1、產生死鎖的必要條件
- 互斥條件:一個資源每次只能被一個執(zhí)行流使用。
- 請求和保持條件:一個執(zhí)行流因請求資源而阻塞時,它同時也持有已有的資源,且不釋放。
- 不剝奪條件:如果申請不到資源,只能等待,不能強行搶占。
- 循環(huán)條件:執(zhí)行流之間形成有環(huán)的等待資源的關系。
2、如何解決
- 破壞上面的 4 條必要條件的其中一條。
- 資源一次性分配。
- 加鎖順序一致。
- 避免未釋放的場景。
三、同步問題
1、什么是同步
同步就是讓線程按照一定順序獲取資源,而不是一窩蜂地去搶。舉個例子,假如廁所是一個共享資源,一次只能一個人用。當有人進去后,就會有很多人在外面等。如果不同步的話,一旦廁所里的那個人出來,全部人就會一窩蜂地去搶廁所;而如果剛出來的那個人的搶占能力非常強,那么廁所就會一直被搶占能力最強的那個人占用,因為這個人可以出來后再搶。于是就會導致其他人長時間沒得上廁所,進而引發(fā)其他人的饑餓問題。
因此,解決方法就是讓所有人排隊,一個個上廁所。從廁所出來的人無論搶占能力強還是弱,都要去隊尾排隊。這種讓人們有序地使用廁所就是同步。而把線程看成人,那就就是線程的同步了。所以,總結來說,在保證數(shù)據(jù)安全的前提下,讓線程能夠按照某種特定的順序訪問臨界資源,從而有效避免饑餓問題,叫做同步。
2、條件變量
2.1. 什么是條件變量
還記得前面廁所排隊的例子嗎?條件變量就是這個等待隊列的頭節(jié)點,當申請到資源時,線程就會從等待隊列出來,然后訪問共享資源;而如果線程沒申請到資源時,該線程就會進入以條件變量為頭節(jié)點的等待隊列里。
2.2. 相關函數(shù)
2.2.0.?pthread_cond_t 類型
該類型為條件變量類型。
2.2.1.?初始化全局的條件變量
pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
2.2.1. 初始化局部變量的條件變量
參數(shù)介紹
- cond:條件變量的地址。
- attr:?條件變量的性質。
這個函數(shù)用于初始化條件變量。其實就是初始化等待隊列的頭節(jié)點。
2.2.2. pthread_cond_destroy 函數(shù)
參數(shù)介紹
- cond:傳條件變量的地址。?
注意:
- 如果創(chuàng)建的條件變量是用宏創(chuàng)建的,就不能掉這個函數(shù)。?
這個函數(shù)用于釋放條件變量。其實就是初始化等待隊列的頭節(jié)點。
2.2.3.?pthread_cond_wait 函數(shù)
參數(shù)介紹
cond:傳條件變量的地址。
mutex:傳互斥鎖的地址。?
此函數(shù)用于把線程加入等待隊列。如果此時沒申請到共享資源,該線程就會進入以條件變量為頭節(jié)點的等待隊列里。
2.2.4.?pthread_cond_signal 函數(shù)
參數(shù)介紹
- cond:條件變量地址。?
此函數(shù)用于喚醒線程。 即當線程申請到共享資源時,這個函數(shù)就能讓一個線程的 TCB 退出以條件變量為頭節(jié)點的等待隊列。
2.2.5.?pthread_cond_broadcast 函數(shù)
參數(shù)介紹
- cond:條件變量地址。?
即當線程申請到共享資源時,這個函數(shù)就能讓所有線程的 TCB 退出以條件變量為頭節(jié)點的等待隊列。?
四、應用:生產者消費者問題(cp 問題)
1、什么是生產者消費者問題
簡單來說,前提就是生產者和消費者之間有一個共享資源(共享內存),生產者負責向共享內存放數(shù)據(jù),消費者負責從共享內存里拿數(shù)據(jù)。然后我們通過一定的策略解決它們的互斥與同步問題。
2、3 種關系
2.1. 生產者與生產者
生產者與生產者之間是競爭關系,因此生產者與生產者之間是互斥關系。
2.2. 生產者與消費者
2.2.1. 互斥關系
因為要保證公共資源的安全性,因此要讓生產者與消費者處于互斥關系,每次只能有一個線程訪問共享資源。
2.2.2. 同步關系
因為共享內存里先有數(shù)據(jù),消費者才可以拿數(shù)據(jù)。而生產者是負責向內存放數(shù)據(jù)的。因此先有生產者向共享內存放數(shù)據(jù),才有消費者從共享內存拿數(shù)據(jù),這是一種順序訪問共享內存;因此生產者與消費者也處于同步關系。
2.3. 消費者與消費者
消費者與消費者之間是競爭關系,因此生產者與生產者之間是互斥關系。