.. SPDX-License-Identifier: GPL-2.0 .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/locking/spinlocks.rst :翻译: å”艺舟 Tang Yizhou <tangyeechou@gmail.com> ========== åŠ é”çš„æ•™è® ========== æ•™è® 1ï¼šè‡ªæ—‹é” ============== åŠ é”æœ€åŸºæœ¬çš„åŽŸè¯æ˜¯è‡ªæ—‹é”(spinlock):: static DEFINE_SPINLOCK(xxx_lock); unsigned long flags; spin_lock_irqsave(&xxx_lock, flags); ... 这里是临界区 .. spin_unlock_irqrestore(&xxx_lock, flags); ä¸Šè¿°ä»£ç æ€»æ˜¯å®‰å…¨çš„。自旋é”将在 _本地_ ç¦ç”¨ä¸æ–,但它本身将ä¿è¯å…¨å±€é”定。所以它 å°†ä¿è¯åœ¨è¯¥é”ä¿æŠ¤çš„åŒºåŸŸå†…åªæœ‰ä¸€ä¸ªæŽ§åˆ¶çº¿ç¨‹ã€‚å³ä½¿åœ¨å•处ç†å™¨ï¼ˆUP)下也能很好的工作, 所以代ç _ä¸_ éœ€è¦æ‹…心UP还是SMP的问题:自旋é”åœ¨ä¸¤ç§æƒ…况下都能æ£å¸¸å·¥ä½œã€‚ 注æ„ï¼è‡ªæ—‹é”对内å˜çš„æ½œåœ¨å½±å“ç”±ä¸‹è¿°æ–‡æ¡£è¿›ä¸€æ¥æè¿°ï¼š Documentation/memory-barriers.txt (5) ACQUIRE operations. (6) RELEASE operations. 上述代ç 通常éžå¸¸ç®€å•ï¼ˆå¯¹å¤§éƒ¨åˆ†æƒ…å†µï¼Œä½ é€šå¸¸éœ€è¦å¹¶ä¸”åªå¸Œæœ›æœ‰ä¸€ä¸ªè‡ªæ—‹é”——使用多个 自旋é”会使事情å˜å¾—æ›´å¤æ‚ï¼Œç”šè‡³æ›´æ…¢ï¼Œè€Œä¸”é€šå¸¸ä»…ä»…åœ¨ä½ **ç†è§£çš„** åºåˆ—有被拆分的 需求时æ‰å€¼å¾—这么åšï¼šå¦‚æžœä½ ä¸ç¡®å®šçš„è¯ï¼Œè¯·ä¸æƒœä¸€åˆ‡ä»£ä»·é¿å…è¿™æ ·åšï¼‰ã€‚ 这是关于自旋é”的唯一真æ£å›°éš¾çš„éƒ¨åˆ†ï¼šä¸€æ—¦ä½ å¼€å§‹ä½¿ç”¨è‡ªæ—‹é”ï¼Œå®ƒä»¬å¾€å¾€ä¼šæ‰©å±•åˆ°ä½ ä»¥å‰ å¯èƒ½æ²¡æœ‰æ³¨æ„åˆ°çš„é¢†åŸŸï¼Œå› ä¸ºä½ å¿…é¡»ç¡®ä¿è‡ªæ—‹é”æ£ç¡®åœ°ä¿æŠ¤å…±äº«æ•°æ®ç»“æž„ **æ¯ä¸€å¤„** 被 ä½¿ç”¨çš„åœ°æ–¹ã€‚è‡ªæ—‹é”æ˜¯æœ€å®¹æ˜“è¢«æ·»åŠ åˆ°å®Œå…¨ç‹¬ç«‹äºŽå…¶å®ƒä»£ç 的地方(例如,没有人访问的 内部驱动数æ®ç»“构)的。 注æ„ï¼ä»…å½“ä½ åœ¨è·¨CPUæ ¸è®¿é—®æ—¶ä½¿ç”¨ **åŒä¸€æŠŠ** 自旋é”ï¼Œå¯¹å®ƒçš„ä½¿ç”¨æ‰æ˜¯å®‰å…¨çš„。 è¿™æ„å‘³ç€æ‰€æœ‰è®¿é—®å…±äº«å˜é‡çš„代ç 必须对它们想使用的自旋é”è¾¾æˆä¸€è‡´ã€‚ ---- æ•™è® 2:读-å†™è‡ªæ—‹é” =================== å¦‚æžœä½ çš„æ•°æ®è®¿é—®æœ‰ä¸€ä¸ªéžå¸¸è‡ªç„¶çš„æ¨¡å¼ï¼Œå€¾å‘于从共享å˜é‡ä¸è¯»å–æ•°æ®ï¼Œè¯»-å†™è‡ªæ—‹é” ï¼ˆrw_lock)有时是有用的。它们å…è®¸å¤šä¸ªè¯»è€…åŒæ—¶å‡ºçŽ°åœ¨åŒä¸€ä¸ªä¸´ç•ŒåŒºï¼Œä½†æ˜¯å¦‚果有人想 改å˜å˜é‡ï¼Œå®ƒå¿…须获得一个独å 的写é”。 注æ„ï¼è¯»-å†™è‡ªæ—‹é”æ¯”原始自旋é”éœ€è¦æ›´å¤šçš„原åå†…å˜æ“作。除éžè¯»è€…的临界区很长, å¦åˆ™ä½ 最好åªä½¿ç”¨åŽŸå§‹è‡ªæ—‹é”。 例程看起æ¥å’Œä¸Šé¢ä¸€æ ·:: rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock); unsigned long flags; read_lock_irqsave(&xxx_lock, flags); .. 仅读å–ä¿¡æ¯çš„临界区 ... read_unlock_irqrestore(&xxx_lock, flags); write_lock_irqsave(&xxx_lock, flags); .. 读å–和独å å†™ä¿¡æ¯ ... write_unlock_irqrestore(&xxx_lock, flags); 上é¢è¿™ç§é”å¯¹äºŽå¤æ‚的数æ®ç»“构如链表å¯èƒ½ä¼šæœ‰ç”¨ï¼Œç‰¹åˆ«æ˜¯åœ¨ä¸æ”¹å˜é“¾è¡¨çš„æƒ…况下æœç´¢å…¶ä¸ çš„æ¡ç›®ã€‚读é”å…许许多并å‘的读者。任何希望 **修改** 链表的代ç 将必须先获å–写é”。 注æ„ï¼RCU锿›´é€‚åˆé历链表,但需è¦ä»”细注æ„设计细节(è§Documentation/RCU/listRCU.rst)。 å¦å¤–ï¼Œä½ ä¸èƒ½æŠŠè¯»é”“å‡çº§â€ä¸ºå†™é”ï¼Œæ‰€ä»¥å¦‚æžœä½ åœ¨ _任何_ 时候需è¦åšä»»ä½•修改 (å³ä½¿ä½ 䏿˜¯æ¯æ¬¡éƒ½è¿™æ ·åšï¼‰ï¼Œä½ 必须在一开始就获得写é”。 注æ„ï¼æˆ‘们æ£åœ¨åŠªåŠ›æ¶ˆé™¤å¤§å¤šæ•°æƒ…å†µä¸‹çš„è¯»-写自旋é”的使用,所以请ä¸è¦åœ¨æ²¡æœ‰è¾¾æˆ å…±è¯†çš„æƒ…å†µä¸‹å¢žåŠ ä¸€ä¸ªæ–°çš„ï¼ˆç›¸å,请å‚阅Documentation/RCU/rcu.rst以获得完整 ä¿¡æ¯ï¼‰ã€‚ ---- æ•™è® 3ï¼šé‡æ–°å®¡è§†è‡ªæ—‹é” ====================== 上述的自旋é”原è¯ç»ä¸æ˜¯å”¯ä¸€çš„。它们是最安全的,在所有情况下都能æ£å¸¸å·¥ä½œï¼Œä½†éƒ¨åˆ† **å› ä¸º** 它们是安全的,它们也是相当慢的。它们比原本需è¦çš„æ›´æ…¢ï¼Œå› ä¸ºå®ƒä»¬å¿…é¡»è¦ ç¦ç”¨ä¸æ–(在X86ä¸Šåªæ˜¯ä¸€æ¡æŒ‡ä»¤ï¼Œä½†å´æ˜¯ä¸€æ¡æ˜‚贵的指令——而在其他体系结构上,情况 å¯èƒ½æ›´ç³Ÿï¼‰ã€‚ å¦‚æžœä½ æœ‰å¿…é¡»ä¿æŠ¤è·¨CPU访问的数æ®ç»“æž„ä¸”ä½ æƒ³ä½¿ç”¨è‡ªæ—‹é”çš„åœºæ™¯ï¼Œä½ æœ‰å¯èƒ½ä½¿ç”¨ä»£ä»·å°çš„ 自旋é”ç‰ˆæœ¬ã€‚å½“ä¸”ä»…å½“ä½ çŸ¥é“æŸè‡ªæ—‹é”永远ä¸ä¼šåœ¨ä¸æ–处ç†ç¨‹åºä¸ä½¿ç”¨ï¼Œä½ å¯ä»¥ä½¿ç”¨éžä¸æ– 的版本:: spin_lock(&lock); ... spin_unlock(&lock); (当然,也å¯ä»¥ä½¿ç”¨ç›¸åº”的读-写é”版本)。这ç§è‡ªæ—‹é”å°†åŒæ ·å¯ä»¥ä¿è¯ç‹¬å 访问,而且 é€Ÿåº¦ä¼šå¿«å¾ˆå¤šã€‚å¦‚æžœä½ çŸ¥é“æœ‰å…³çš„æ•°æ®åªåœ¨â€œè¿›ç¨‹ä¸Šä¸‹æ–‡â€ä¸è¢«å˜å–,å³ï¼Œä¸æ¶‰åŠä¸æ–, è¿™ç§è‡ªæ—‹é”就有用了。 å½“è¿™äº›ç‰ˆæœ¬çš„è‡ªæ—‹é”æ¶‰åŠä¸æ–æ—¶ï¼Œä½ ä¸èƒ½ä½¿ç”¨çš„åŽŸå› æ˜¯ä¼šé™·å…¥æ»é”:: spin_lock(&lock); ... <- 䏿–æ¥ä¸´ï¼š spin_lock(&lock); ä¸€ä¸ªä¸æ–试图对一个已ç»é”定的å˜é‡ä¸Šé”ã€‚å¦‚æžœä¸æ–å‘生在å¦ä¸€ä¸ªCPU上,ä¸ä¼šæœ‰é—®é¢˜ï¼› ä½†å¦‚æžœä¸æ–å‘ç”Ÿåœ¨å·²ç»æŒæœ‰è‡ªæ—‹é”çš„åŒä¸€ä¸ªCPU上,将 _会_ æœ‰é—®é¢˜ï¼Œå› ä¸ºè¯¥é”æ˜¾ç„¶æ°¸è¿œ ä¸ä¼šè¢«é‡Šæ”¾ï¼ˆå› ä¸ºä¸æ–æ£åœ¨ç‰å¾…该é”,而é”çš„æŒæœ‰è€…è¢«ä¸æ–打æ–ï¼Œå¹¶ä¸”æ— æ³•ç»§ç»æ‰§è¡Œï¼Œ ç›´åˆ°ä¸æ–处ç†ç»“æŸï¼‰ã€‚ (这也是自旋é”çš„ä¸æ–版本åªéœ€è¦ç¦ç”¨ _本地_ 䏿–çš„åŽŸå› â€”â€”åœ¨å‘生于其它CPUçš„ä¸æ–ä¸ ä½¿ç”¨åŒä¸€æŠŠè‡ªæ—‹é”æ˜¯æ²¡é—®é¢˜çš„ï¼Œå› ä¸ºå‘生于其它CPUçš„ä¸æ–ä¸ä¼šæ‰“æ–å·²ç»æŒé”çš„CPU,所以 é”çš„æŒæœ‰è€…å¯ä»¥ç»§ç»æ‰§è¡Œå¹¶æœ€ç»ˆé‡Šæ”¾é”)。 Linus ---- å‚è€ƒä¿¡æ¯ ======== 对于动æ€åˆå§‹åŒ–,使用spin_lock_init()或rwlock_init()是åˆé€‚çš„:: spinlock_t xxx_lock; rwlock_t xxx_rw_lock; static int __init xxx_init(void) { spin_lock_init(&xxx_lock); rwlock_init(&xxx_rw_lock); ... } module_init(xxx_init); å¯¹äºŽé™æ€åˆå§‹åŒ–,使用DEFINE_SPINLOCK() / DEFINE_RWLOCK()或 __SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED()是åˆé€‚的。