1.Linux读写锁逻辑解析
2.spinlock(linux kernel 自旋锁)
3.Go并åç¼ç¨ï¼goroutineï¼channelåsync详解
Linux读写锁逻辑解析
Linux的源码读写锁机制,如同一把精密的源码多线程调和器,巧妙解决并发世界中的源码读多写少困境。其核心数据结构,源码如rwsem(读写信号量),源码包含读写状态counter和任务管理信息,源码java 商城源码下载确保了读线程的源码并发性和写线程的互斥性。
在内核设计中,源码当写线程尝试获取写锁时,源码可能会采取乐观自旋策略,源码若失败则会优雅地加入等待队列。源码rw_semaphore结构体中的源码关键成员,如task指针和队列,源码负责管理这些等待任务。源码对外API如down_read_trylock,源码为高效读取提供了可能,黑客团队网站源码即使尝试失败也不会造成阻塞。
读锁获取过程复杂而微妙,通过RWSEM_READER_BIAS快速路径和防止饿死的慢速路径,遵循公平原则。乐观偷锁机制允许临界区无写者时,高优先级读者尝试先入。若偷窃失败,读者会进入等待队列,队列超时机制确保效率与公平的平衡。
当读线程加入等待队列,任务会被细致地处理,通过rwsem_add_waiter调整counter。特别是对于首位等待者,会设置RWSEM_FLAG_WAITERS标志。在尝试获取锁前,彩虹挂q 源码可能需要唤醒潜在的等待者,如owner离开或读锁持有者。释放读锁时,仅简单地减去counter,不移除owner,以减少复杂性。
写锁的获取则更为严谨,rwsem_write_trylock会检查rwsem状态,成功则立即持有并标记,否则返回。写锁的获取过程涉及等待队列的操作和唤醒策略,保证了高优先级的请求能及时响应。
在写锁持有者释放时,与读锁类似,仅清理owner,dxf转gcode源码同时考虑writer可能对reader的抢锁影响。乐观自旋条件的判断,确保了在特定场景下的高效执行,如writer持有锁且未禁止自旋。
OPPO内核团队在实际应用中,如手机交互场景,对Linux读写锁进行了优化,以降低延迟和提高吞吐量。深入研究5..内核源代码中的"Documentation\locking\"部分,你会发现更多优化细节。对于对技术感兴趣的读者,"内核工匠"公众号提供了丰富的技术内容。
Linux的读写锁设计,如同一个精密的调和大师,它在并发世界中奏出了平衡、服装pos c 源码效率与公平的交响乐,无论在理论层面还是实际应用中,都展现出强大的适应性和灵活性,是多线程并发编程的有力工具。
spinlock(linux kernel 自旋锁)
"锁"的使命在于保护临界资源,防止多CPU同时访问相同变量,避免数据一致性问题。非原子变量的修改无法在单指令周期内完成,若CPU1更改变量中途,CPU2访问该半成品变量,可能导致严重后果。解决方法是CPU1在修改变量前先"加锁",CPU2在访问变量前也加锁,由于已经被加锁,CPU2将原地等待锁释放。CPU1完成修改后"解锁",CPU2获取锁后加锁访问变量,完成后解锁。自旋锁(spinlock)与信号量、互斥锁不同,等待锁释放时不睡眠,而是自旋。不睡眠的优点是适用于中断上下文运行,且对于快速获取锁的场景效率更高。缺点是长时间等待锁释放会浪费大量CPU资源。
spinlock适用于中断上下文和进程上下文,因此在内核中广泛应用。内核开发者关注其执行效率,spinlock方案经历了多次优化。简单介绍如下:
首先,理解锁的优化,要从一个线程加锁,一千个线程等待锁的极端场景出发。有三种常见模式:
1. CAS模式(Compare And Swap):
通过原子变量控制。加锁时,获取变量为1,获取锁后修改为0。解锁时,将变量修改回1。优点是简单易懂,但存在竞争随机性,等待时间不确定。
2. Ticket模式:
解决CAS模式的随机竞争问题。锁包含tail值,加锁时保存本地变量,将tail+1,与锁的head对比,若相等则持有锁。解锁时,将head+1,所有等待的线程重新读取内存,确认是否轮到自己持有锁。优点是实现公平,先到先得,但浪费CPU资源。
3.MCS模式(Mellor-Crummey and Scott):
解决Ticket模式的CPU浪费问题。使用单向链表实现顺序通知,效率更高,但结构体中使用指针,占用内存空间。MCS相比Ticket多出4字节内存,但自旋锁在内核中频繁使用,追求极致效率的开发者不能容忍这种浪费。
最终形态为qspinlock,基于MCS模式改进,节省内存开销,保持高效执行。使用步骤包括包含头文件、定义自旋锁、初始化、加锁解锁。API适应中断嵌套和进程混合加锁,不考虑中断抢占时有其他接口。源码路径包括kernel\locking\spinlock.c、kernel\locking\qspinlock.c和include\linux\spinlock.h。原理阐述较多,代码解析不多,简单查看spin的层级即可。spinlock方案的演进对开发者无感,内核开发者可以轻松升级spin方案。更多内容请参阅RTFSC专栏。
Go并åç¼ç¨ï¼goroutineï¼channelåsync详解
ä¼é ç并åç¼ç¨èå¼ï¼å®åç并åæ¯æï¼åºè²ç并åæ§è½æ¯Goè¯è¨åºå«äºå ¶ä»è¯è¨çä¸å¤§ç¹è²ãå¨å½ä»è¿ä¸ªå¤æ ¸æ¶ä»£ï¼å¹¶åç¼ç¨çæä¹ä¸è¨èå»ã使ç¨Goå¼å并åç¨åºï¼æä½èµ·æ¥é常ç®åï¼è¯è¨çº§å«æä¾å ³é®ågoç¨äºå¯å¨åç¨ï¼å¹¶ä¸å¨åä¸å°æºå¨ä¸å¯ä»¥å¯å¨æåä¸ä¸ä¸ªåç¨ã
ä¸é¢å°±æ¥è¯¦ç»ä»ç»ã
goroutineGoè¯è¨ç并åæ§è¡ä½ç§°ä¸ºgoroutineï¼ä½¿ç¨å ³é®è¯goæ¥å¯å¨ä¸ä¸ªgoroutineã
goå ³é®è¯åé¢å¿ é¡»è·ä¸ä¸ªå½æ°ï¼å¯ä»¥æ¯æåå½æ°ï¼ä¹å¯ä»¥æ¯æ åå½æ°ï¼å½æ°çè¿åå¼ä¼è¢«å¿½ç¥ã
goçæ§è¡æ¯éé»å¡çã
å æ¥çä¸ä¸ªä¾åï¼
packagemainimport("fmt""time")funcmain(){ gospinner(*time.Millisecond)constn=fibN:=fib(n)fmt.Printf("\rFibonacci(%d)=%d\n",n,fibN)//Fibonacci()=}funcspinner(delaytime.Duration){ for{ for_,r:=range`-\|/`{ fmt.Printf("\r%c",r)time.Sleep(delay)}}}funcfib(xint)int{ ifx<2{ returnx}returnfib(x-1)+fib(x-2)}ä»æ§è¡ç»ææ¥çï¼æå计ç®åºäºææ³¢é£å¥æ°åçå¼ï¼è¯´æç¨åºå¨spinnerå¤å¹¶æ²¡æé»å¡ï¼èä¸spinnerå½æ°è¿ä¸ç´å¨å±å¹ä¸æå°æ示å符ï¼è¯´æç¨åºæ£å¨æ§è¡ã
å½è®¡ç®å®ææ³¢é£å¥æ°åçå¼ï¼mainå½æ°æå°ç»æ并éåºï¼spinnerä¹è·çéåºã
åæ¥çä¸ä¸ªä¾åï¼å¾ªç¯æ§è¡æ¬¡ï¼æå°ä¸¤ä¸ªæ°çåï¼
packagemainimport"fmt"funcAdd(x,yint){ z:=x+yfmt.Println(z)}funcmain(){ fori:=0;i<;i++{ goAdd(i,i)}}æé®é¢äºï¼å±å¹ä¸ä»ä¹é½æ²¡æï¼ä¸ºä»ä¹å¢ï¼
è¿å°±è¦çGoç¨åºçæ§è¡æºå¶äºãå½ä¸ä¸ªç¨åºå¯å¨æ¶ï¼åªæä¸ä¸ªgoroutineæ¥è°ç¨mainå½æ°ï¼ç§°ä¸ºä¸»goroutineãæ°çgoroutineéè¿goå ³é®è¯å建ï¼ç¶å并åæ§è¡ãå½mainå½æ°è¿åæ¶ï¼ä¸ä¼çå¾ å ¶ä»goroutineæ§è¡å®ï¼èæ¯ç´æ¥æ´åç»ææægoroutineã
é£æ没æåæ³è§£å³å¢ï¼å½ç¶æ¯æçï¼è¯·å¾ä¸çã
channelä¸è¬åå¤è¿ç¨ç¨åºæ¶ï¼é½ä¼éå°ä¸ä¸ªé®é¢ï¼è¿ç¨é´éä¿¡ã常è§çéä¿¡æ¹å¼æä¿¡å·ï¼å ±äº«å åçãgoroutineä¹é´çéä¿¡æºå¶æ¯ééchannelã
使ç¨makeå建ééï¼
ch:=make(chanint)//chçç±»åæ¯chanintééæ¯æä¸ä¸ªä¸»è¦æä½ï¼sendï¼receiveåcloseã
ch<-x//åéx=<-ch//æ¥æ¶<-ch//æ¥æ¶ï¼ä¸¢å¼ç»æclose(ch)//å ³éæ ç¼å²channelmakeå½æ°æ¥å两个åæ°ï¼ç¬¬äºä¸ªåæ°æ¯å¯éåæ°ï¼è¡¨ç¤ºéé容éãä¸ä¼ æè ä¼ 0表示å建äºä¸ä¸ªæ ç¼å²ééã
æ ç¼å²ééä¸çåéæä½å°ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineå¨å¯¹åºçééä¸æ§è¡æ¥æ¶æä½ãç¸åï¼å¦ææ¥æ¶å æ§è¡ï¼é£ä¹æ¥æ¶goroutineå°ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineå¨å¯¹åºééä¸æ§è¡åéã
æ以ï¼æ ç¼å²ééæ¯ä¸ç§åæ¥ééã
ä¸é¢æ们使ç¨æ ç¼å²ééæä¸é¢ä¾åä¸åºç°çé®é¢è§£å³ä¸ä¸ã
packagemainimport"fmt"funcAdd(x,yint,chchanint){ z:=x+ych<-z}funcmain(){ ch:=make(chanint)fori:=0;i<;i++{ goAdd(i,i,ch)}fori:=0;i<;i++{ fmt.Println(<-ch)}}å¯ä»¥æ£å¸¸è¾åºç»æã
主goroutineä¼é»å¡ï¼ç´å°è¯»åå°ééä¸çå¼ï¼ç¨åºç»§ç»æ§è¡ï¼æåéåºã
ç¼å²channelå建ä¸ä¸ªå®¹éæ¯5çç¼å²ééï¼
ch:=make(chanint,5)ç¼å²ééçåéæä½å¨ééå°¾é¨æå ¥ä¸ä¸ªå ç´ ï¼æ¥æ¶æä½ä»ééç头é¨ç§»é¤ä¸ä¸ªå ç´ ãå¦æéé满äºï¼åéä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineæ§è¡æ¥æ¶ãç¸åï¼å¦æééæ¯ç©ºçï¼æ¥æ¶ä¼é»å¡ï¼ç´å°å¦ä¸ä¸ªgoroutineæ§è¡åéã
æ没ææè§ï¼å ¶å®ç¼å²ééåéåä¸æ ·ï¼ææä½é½è§£è¦äºã
ååchannelç±»åchan<-intæ¯ä¸ä¸ªåªè½åéçééï¼ç±»å<-chanintæ¯ä¸ä¸ªåªè½æ¥æ¶çééã
ä»»ä½ååééé½å¯ä»¥ç¨ä½ååééï¼ä½åè¿æ¥ä¸è¡ã
è¿æä¸ç¹éè¦æ³¨æï¼closeåªè½ç¨å¨åéééä¸ï¼å¦æç¨å¨æ¥æ¶ééä¼æ¥éã
çä¸ä¸ªååééçä¾åï¼
packagemainimport"fmt"funccounter(outchan<-int){ forx:=0;x<;x++{ out<-x}close(out)}funcsquarer(outchan<-int,in<-chanint){ forv:=rangein{ out<-v*v}close(out)}funcprinter(in<-chanint){ forv:=rangein{ fmt.Println(v)}}funcmain(){ n:=make(chanint)s:=make(chanint)gocounter(n)gosquarer(s,n)printer(s)}syncsyncå æä¾äºä¸¤ç§éç±»åï¼sync.Mutexåsync.RWMutexï¼åè æ¯äºæ¥éï¼åè æ¯è¯»åéã
å½ä¸ä¸ªgoroutineè·åäºMutexåï¼å ¶ä»goroutineä¸ç®¡è¯»åï¼åªè½çå¾ ï¼ç´å°é被éæ¾ã
packagemainimport("fmt""sync""time")funcmain(){ varmutexsync.Mutexwg:=sync.WaitGroup{ }//主goroutineå è·åéfmt.Println("Locking(G0)")mutex.Lock()fmt.Println("locked(G0)")wg.Add(3)fori:=1;i<4;i++{ gofunc(iint){ //ç±äºä¸»goroutineå è·åéï¼ç¨åºå¼å§5ç§ä¼é»å¡å¨è¿éfmt.Printf("Locking(G%d)\n",i)mutex.Lock()fmt.Printf("locked(G%d)\n",i)time.Sleep(time.Second*2)mutex.Unlock()fmt.Printf("unlocked(G%d)\n",i)wg.Done()}(i)}//主goroutine5ç§åéæ¾étime.Sleep(time.Second*5)fmt.Println("readyunlock(G0)")mutex.Unlock()fmt.Println("unlocked(G0)")wg.Wait()}RWMutexå±äºç»å ¸çååå¤è¯»æ¨¡åï¼å½è¯»é被å ç¨æ¶ï¼ä¼é»æ¢åï¼ä½ä¸é»æ¢è¯»ãèåéä¼é»æ¢åå读ã
packagemainimport("fmt""sync""time")funcmain(){ varrwMutexsync.RWMutexwg:=sync.WaitGroup{ }Data:=0wg.Add()fori:=0;i<;i++{ gofunc(tint){ //第ä¸æ¬¡è¿è¡åï¼å解éã//循ç¯å°ç¬¬äºæ¬¡æ¶ï¼è¯»éå®åï¼goroutine没æé»å¡ï¼åæ¶è¯»æåãfmt.Println("Locking")rwMutex.RLock()deferrwMutex.RUnlock()fmt.Printf("Readdata:%v\n",Data)wg.Done()time.Sleep(2*time.Second)}(i)gofunc(tint){ //åéå®ä¸æ¯éè¦è§£éåæè½åçrwMutex.Lock()deferrwMutex.Unlock()Data+=tfmt.Printf("WriteData:%v%d\n",Data,t)wg.Done()time.Sleep(2*time.Second)}(i)}wg.Wait()}æ»ç»å¹¶åç¼ç¨ç®æ¯Goçç¹è²ï¼ä¹æ¯æ ¸å¿åè½ä¹ä¸äºï¼æ¶åçç¥è¯ç¹å ¶å®æ¯é常å¤çï¼æ¬æä¹åªæ¯èµ·å°ä¸ä¸ªæç å¼ççä½ç¨èå·²ã
æ¬æå¼å§ä»ç»äºgoroutineçç®åç¨æ³ï¼ç¶åå¼åºäºééçæ¦å¿µã
ééæä¸ç§ï¼
æ ç¼å²éé
ç¼å²éé
ååéé
æåä»ç»äºGoä¸çéæºå¶ï¼åå«æ¯syncå æä¾çsync.Mutexï¼äºæ¥éï¼åsync.RWMutexï¼è¯»åéï¼ã
goroutineå大精深ï¼åé¢çåè¿æ¯è¦æ ¢æ ¢è¸©çã
æç« ä¸çèå¾åæºç é½ä¸ä¼ å°äºGitHubï¼æéè¦çåå¦å¯èªè¡ä¸è½½ã
å°åï¼github.com/yongxinz/gopher/tree/main/sc
ä½è ï¼yongxinz