6.3.1 linux 自旋鎖進階

自旋鎖常用api

1,為什么除了spin_lock() api還定義了spin_lock_irq()等翅睛。

因為:spin_lock()可以防止線程調(diào)度,但不能防止硬件中斷的到來鸣皂,以及隨后的中斷處理函數(shù)(hardirq)的執(zhí)行。
假設一個CPU上的線程T持有了一個spinlock习柠,發(fā)生中斷后芳来,該CPU轉而執(zhí)行對應的hardirq梆暮。如果該hardirq也試圖去持有這個spinlock捉超,那么將無法獲取成功胧卤,導致hardirq無法退出。在hardirq主動退出之前拼岳,線程T是無法繼續(xù)執(zhí)行以釋放spinlock的枝誊,最終將導致該CPU上的代碼不能繼續(xù)向前運行,形成死鎖(dead lock)裂问,
因此如果spin_lock()鎖住得臨界區(qū)可能被中斷打斷侧啼,要使用spin_lock_irq()或者spin_lock_irqsave()
但是即便使用了spin_lock_irqsave()只能關閉本CPU中斷,如果其他CPU上發(fā)生了中斷堪簿,那么這些CPU上的hardirq,也有可能試圖去獲取一個被本地CPU上運行的線程T占有的spinlock皮壁。
不過沒有關系椭更,因為此時hardirq和線程T運行在不同的CPU上,等到線程T繼續(xù)運行釋放了這個spinlock蛾魄,hardirq就有機會獲取到虑瀑,不至于造成死鎖。

2滴须,單核cpu使用spin_lock()會出現(xiàn)死鎖嗎舌狗。

不會,因為spin_lock()關閉了搶占扔水,只能按照順序執(zhí)行痛侍,只要不發(fā)生中斷是不會發(fā)生死鎖的,但是若臨界區(qū)可能發(fā)生中斷仍然可能死鎖魔市。

3主届,自旋鎖是怎么搶占的赵哲。
4,自旋鎖與互斥鎖的區(qū)別

自旋鎖和互斥鎖用于處理內(nèi)核中并發(fā)訪問君丁,它們有各自的使用對象枫夺。·
互斥鎖保護進程的關鍵資源绘闷,而自旋鎖保護IRQ處理程序的關鍵部分橡庞。·互斥鎖讓競爭者在獲得鎖之前睡眠印蔗,而自旋鎖在獲得鎖之前一直自旋循環(huán)(消耗CPU)毙死。·
鑒于上一點喻鳄,自旋鎖不能長時間持有扼倘,因為等待者在等待取鎖期間會浪費CPU時間;而互斥鎖則可以長時間持有除呵,只要保護資源需要再菊,
因為競爭者被放入等待隊列中進入睡眠狀態(tài)。[插圖]當處理自旋鎖時颜曾,
請牢記:只是持有自旋鎖線程搶占被禁止纠拔,而自旋鎖的等待者沒有禁止搶占。

自旋鎖內(nèi)核實現(xiàn)

自旋鎖結構體定義
typedef struct spinlock {
    union {
        struct raw_spinlock rlock;

#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
        struct {
            u8 __padding[LOCK_PADSIZE];
            struct lockdep_map dep_map;
        };
#endif
    };
} spinlock_t;

typedef struct raw_spinlock {
    arch_spinlock_t raw_lock;
#ifdef CONFIG_DEBUG_SPINLOCK
    unsigned int magic, owner_cpu;
    void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map dep_map;
#endif
} raw_spinlock_t;

typedef struct {
    union {
        u32 slock;
        struct __raw_tickets {
#ifdef __ARMEB__
            u16 next;
            u16 owner;
#else
            u16 owner;
            u16 next;
#endif
        } tickets;
    };
} arch_spinlock_t;
spin_lock_irqsave實現(xiàn)
#define spin_lock_irqsave(lock, flags)              \
do {                                \
    raw_spin_lock_irqsave(spinlock_check(lock), flags); \
} while (0)
#define raw_spin_lock_irqsave(lock, flags)          \
    do {                        \
        typecheck(unsigned long, flags);    \
        flags = _raw_spin_lock_irqsave(lock);   \
    } while (0)
對于單核
/*
 * 定義在include/linux/spinlock_api_up.h中 
 * 對于單核自旋鎖的功能就被弱化為禁止搶占泛豪,
 * 最終實際只執(zhí)行的是preempt_disable()-關閉搶占
 */
#define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags)

#define __LOCK_IRQSAVE(lock, flags) \
  do { local_irq_save(flags); __LOCK(lock); } while (0)
/*
* 在arm體系結構中定義如下
 * In the UP-nondebug case there's no real locking going on, so the
 * only thing we have to do is to keep the preempt counts and irq
 * flags straight, to suppress compiler warnings of unused lock
 * variables, and to add the proper checker annotations:
 */
#define ___LOCK(lock) \
  do { __acquire(lock); (void)(lock); } while (0)
  
#define __LOCK(lock) \
  do { preempt_disable(); ___LOCK(lock); } while (0)
對于多核
/*
 * 定義在include/linux/spinlock_api_smp.h中 
 * 多核比較復雜稠诲,
 */
static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
    return flags;
}
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
    __acquire(lock);
    arch_spin_lock(&lock->raw_lock);
    mmiowb_spin_lock();
}
/*
 * 在arm體系結構中
 *ARMv6 ticket-based spin-locking.
 * A memory barrier is required after we get a lock, and before we
 * release it, because V6 CPUs are assumed to have weakly ordered
 * memory.
 */

static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    unsigned long tmp;
    u32 newval;
    arch_spinlock_t lockval;

    prefetchw(&lock->slock);
    __asm__ __volatile__(
"1: ldrex   %0, [%3]\n"
"   add %1, %0, %4\n"
"   strex   %2, %1, [%3]\n"
"   teq %2, #0\n"
"   bne 1b"
    : "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
    : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
    : "cc");

    while (lockval.tickets.next != lockval.tickets.owner) {
        wfe();
        lockval.tickets.owner = READ_ONCE(lock->tickets.owner);
    }

    smp_mb();
}

參考:
https://www.ixigua.com/6940602677994717708?id=6872657862988923392&logTag=79b91f342c90aac06619
https://www.cnblogs.com/sky-heaven/p/13602357.html
https://mp.weixin.qq.com/s/viUgMAnVgC_bHyVifkHqsQ
https://mp.weixin.qq.com/s/mosYi_W-Rp1-HgdtxUqSEg

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市诡曙,隨后出現(xiàn)的幾起案子臀叙,更是在濱河造成了極大的恐慌,老刑警劉巖价卤,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劝萤,死亡現(xiàn)場離奇詭異,居然都是意外死亡慎璧,警方通過查閱死者的電腦和手機床嫌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胸私,“玉大人厌处,你說我怎么就攤上這事∷晏郏” “怎么了阔涉?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我洒敏,道長龄恋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任凶伙,我火速辦了婚禮郭毕,結果婚禮上,老公的妹妹穿的比我還像新娘函荣。我一直安慰自己显押,他們只是感情好,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布傻挂。 她就那樣靜靜地躺著乘碑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪金拒。 梳的紋絲不亂的頭發(fā)上兽肤,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機與錄音绪抛,去河邊找鬼资铡。 笑死,一個胖子當著我的面吹牛幢码,可吹牛的內(nèi)容都是我干的笤休。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼症副,長吁一口氣:“原來是場噩夢啊……” “哼店雅!你這毒婦竟也來了?” 一聲冷哼從身側響起贞铣,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤闹啦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咕娄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亥揖,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年圣勒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摧扇。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡圣贸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扛稽,到底是詐尸還是另有隱情吁峻,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站用含,受9級特大地震影響矮慕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜啄骇,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一痴鳄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缸夹,春花似錦痪寻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芽唇,卻和暖如春顾画,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匆笤。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工研侣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疚膊。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓义辕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寓盗。 傳聞我的和親對象是個殘疾皇子灌砖,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spinlock 是內(nèi)核中提供的一種比較常見的鎖機制,自旋鎖是“原地等待”的方式解決資源沖突的傀蚌,即基显,一個線程獲取了...
    日積跬步閱讀 612評論 0 0
  • POSIX threads(簡稱Pthreads)是在多核平臺上進行并行編程的一套常用的API。線程同步(Thre...
    北辰青閱讀 993評論 0 1
  • 自旋鎖(spin lock)與互斥量(mutex)的比較 自旋鎖是一種非阻塞鎖善炫,也就是說撩幽,如果某線程需要獲取自旋鎖...
    lfp901020閱讀 5,330評論 0 4
  • 1. 什么是自旋鎖 自旋鎖與互斥鎖有點類似,但是自旋鎖不會引起調(diào)用者阻塞箩艺,如果自旋鎖已經(jīng)被別的執(zhí)行單元保持窜醉,調(diào)用者...
    cpp加油站閱讀 6,160評論 0 6
  • 1 臨界區(qū) 1.1簡介 在早期計算機系統(tǒng)中,只有一個任務進程在執(zhí)行艺谆,并不存在資源的共享與競爭榨惰。隨著技術和需求的飛速...
    Fly晴天里Fly閱讀 9,031評論 2 13