免費(fèi)空間 個(gè)人網(wǎng)站 google廣告聯(lián)盟營銷管理
個(gè)人主頁:C++忠實(shí)粉絲
歡迎 點(diǎn)贊👍 收藏? 留言? 加關(guān)注💓本文由 C++忠實(shí)粉絲 原創(chuàng)多線程 - 自旋鎖
收錄于專欄[Linux學(xué)習(xí)]
本專欄旨在分享學(xué)習(xí)Linux的一點(diǎn)學(xué)習(xí)筆記,歡迎大家在評論區(qū)交流討論💌
目錄
概述
原理?
優(yōu)點(diǎn)與缺點(diǎn)?
優(yōu)點(diǎn)
缺點(diǎn)?
使用場景?
自旋鎖偽代碼實(shí)現(xiàn)
Linux 提供的自旋鎖系統(tǒng)調(diào)用
注意事項(xiàng)
結(jié)論?
案例代碼?
概述
自旋鎖是一種多線程同步機(jī)制,用于保護(hù)共享資源免受并發(fā)訪問的影響。在多個(gè)線程嘗試獲取鎖時(shí),它們會持續(xù)自旋(即在一個(gè)循環(huán)中不斷檢查鎖是否可用)而不是立即進(jìn)入休眠狀態(tài)等待鎖的釋放。這種機(jī)制減少了線程切換的開銷,適用于短時(shí)間內(nèi)鎖的競爭情況,但是不合理的使用,可能會造成 CPU 的浪費(fèi)。?
原理?
自旋鎖通常使用一個(gè)共享的標(biāo)志位(如一個(gè)布爾值)來表示鎖的狀態(tài)。當(dāng)標(biāo)志位為 true 時(shí),表示鎖已被某個(gè)線程占用;當(dāng)標(biāo)志位為 false 時(shí),表示鎖可用。當(dāng)一個(gè)線程嘗試獲取自旋鎖時(shí),它會不斷檢查標(biāo)志位:
1. 如果標(biāo)志位為 false,表示鎖可用,線程將設(shè)置標(biāo)志位為 true,表示自己占用了鎖,并進(jìn)入臨界區(qū)。
2. 如果標(biāo)志位為 true(即鎖已被其他線程占用),線程會在一個(gè)循環(huán)中不斷自旋等待,直到鎖被釋放。?
優(yōu)點(diǎn)與缺點(diǎn)?
優(yōu)點(diǎn)
1. 低延遲:自旋鎖使用于短時(shí)間內(nèi)的鎖競爭情況,因?yàn)樗粫尵€程進(jìn)入休眠狀態(tài),從而避免了線程轉(zhuǎn)換的開銷,提高了操作系統(tǒng)的效率。
2. 減少了系統(tǒng)調(diào)度開銷: 當(dāng)多個(gè)線程同時(shí)自旋等待同一個(gè)鎖時(shí),如果沒有適當(dāng)?shù)耐吮懿呗?#xff0c;可能會導(dǎo)致所有線程都在不斷檢查鎖狀態(tài)而無法進(jìn)入臨界區(qū),形成活鎖。
缺點(diǎn)?
1. CPU 資源浪費(fèi):如果鎖的持有時(shí)間較長,等待獲取鎖的線程會一直循環(huán)等待,導(dǎo)致 CPU 資源的浪費(fèi)。
2. 可能引起活鎖:當(dāng)多個(gè)線程同時(shí)自旋等待同一個(gè)鎖時(shí),如果沒有適當(dāng)?shù)耐吮懿呗?#xff0c;可能會導(dǎo)致所有線程都在不斷地檢查鎖狀態(tài)而無法進(jìn)入臨界區(qū),形成活鎖。?
使用場景?
1. 短暫等待地情況:使用于鎖被占用時(shí)間很短地場景,如多線程對共享數(shù)據(jù)進(jìn)行簡單的讀寫操作。
2. 多線程的使用:通常用于系統(tǒng)底層,同步多個(gè) CPU 對共享資源的訪問。?
自旋鎖偽代碼實(shí)現(xiàn)
自旋鎖的實(shí)現(xiàn)通常使用原子操作來保證操作的原子性,常用的軟件實(shí)現(xiàn)方式是通過 CAS(Compare-And-Swap)指令實(shí)現(xiàn)。以下是一個(gè)簡單的自旋鎖實(shí)現(xiàn)示例(偽代碼):
#include <stdio.h>
#include <stdatomic.h>
#include <pthread.h>
#include <unistd.h>
// 使用原子標(biāo)志來模擬自旋鎖
atomic_flag spinlock = ATOMIC_FLAG_INIT; // ATOMIC_FLAG_INIT 是0
// 嘗試獲取鎖
void spinlock_lock()
{while (atomic_flag_test_and_set(&spinlock)){// 如果鎖被占用,則忙等待}
}
// 釋放鎖
void spinlock_unlock()
{atomic_flag_clear(&spinlock);
}
typedef _Atomic struct
{
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1_Bool __val;
#elseunsigned char __val;
#endif
} atomic_flag;
功能描述:
atomic_flag_test_and_set 函數(shù)檢查 atomic_flag 的當(dāng)前狀態(tài)。如果 atomic_flag 之前沒有被設(shè)置過(即其值為 false 或 未設(shè)置 狀態(tài)),則函數(shù)會將其設(shè)置為 true(或 設(shè)置 狀態(tài)),并返回先前的值(在這種情況下為 false)。如果 atomic_flag 之前已經(jīng)被設(shè)置過(即其值為 true),則函數(shù)不會改變其狀態(tài),但會返回 true。
原子性:
這個(gè)操作是原子的,意味著在多線程環(huán)境中,它保證了對 atomic_flag 的讀取和修改是不可分割的。當(dāng)一個(gè)線程調(diào)用此函數(shù)時(shí),其他線程無法看到這個(gè)操作的任何中間狀態(tài),這確保了操作的安全性。
Linux 提供的自旋鎖系統(tǒng)調(diào)用
#include <pthread.h>
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);
注意事項(xiàng)
1. 在使用自旋鎖時(shí),需要確保鎖被釋放的時(shí)間盡可能短,以避免 CPU 資源的浪費(fèi)。
2. 在多 CPU 環(huán)境下,自旋鎖可能不如其他鎖機(jī)制高效,因?yàn)樗赡軐?dǎo)致線程在不同的 CPU 上自旋等待。
結(jié)論?
自旋鎖是一種適用于短時(shí)間內(nèi)競爭情況的同步機(jī)制,它通過減少線程切換的開銷來提高鎖操作的效率。然而,它存在 CPU 資源浪費(fèi)和可能引起活鎖等缺點(diǎn)。在使用自旋鎖時(shí),需要根據(jù)具體的應(yīng)用場景進(jìn)行選擇,并確保鎖被釋放的時(shí)間盡可能短。?
案例代碼?
// 操作共享變量會有問題的售票系統(tǒng)代碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>int ticket = 1000;
pthread_spinlock_t lock;void *route(void *arg)
{char *id = (char *)arg;while (1){pthread_spin_lock(&lock);if (ticket > 0){usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;pthread_spin_unlock(&lock);}else{pthread_spin_unlock(&lock);break;}}return nullptr;
}int main(void)
{pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);pthread_spin_destroy(&lock);return 0;
}