【站长工具整站源码】【灵犀外卖源码】【liteos 内核源码】futex源码

时间:2024-12-22 22:55:27 编辑:heibernate源码 来源:uc红包雨源码

1.LockSupport的park等待的底层实现
2.深入探秘高性能并发:C++如何在Linux巧妙应用Futex实现线程锁同步(ob_latch.cpp篇)大篇幅(3万字)
3.实习面试总结 -> fork与🔒
4.深入解析 go 互斥锁 mutex 源码
5.什么是futex?
6.Android 10属性系统原理,检测与定制源码反检测

futex源码

LockSupport的park等待的底层实现

       ä»Žä¸Šä¸€ç¯‡æ–‡ç« ä¸­çš„JDK的延迟队列中,最终是通过LockSupport.park实现线程的等待,那么底层是如何实现等待和超时等待的?本文我们来探讨一下。

LockSupport的park和unpark的方法publicstaticvoidpark(){ UNSAFE.park(false,0L);}publicstaticvoidparkNanos(longnanos){ if(nanos>0)UNSAFE.park(false,nanos);}publicstaticvoidunpark(Threadthread){ if(thread!=null)UNSAFE.unpark(thread);}

       ä»Žä¸Šé¢å¯ä»¥çœ‹åˆ°å®žé™…LockSupport.park是通过Unsafe的的park方法实现,从下面的方法可以看出这个是一个native方法.

/***Blockscurrentthread,returningwhenabalancing*{ @codeunpark}occurs,orabalancing{ @codeunpark}has*alreadyoccurred,orthethreadisinterrupted,or,ifnot*absoluteandtimeisnotzero,thegiventimenanosecondshave*elapsed,orifabsolute,thegivendeadlineinmilliseconds*sinceEpochhaspassed,orspuriously(i.e.,returningforno*"reason").Note:ThisoperationisintheUnsafeclassonly*because{ @codeunpark}is,soitwouldbestrangetoplaceit*elsewhere.*/publicnativevoidpark(booleanisAbsolute,longtime);JVM的Unsafe的park方法

       ä»Žä¸‹é¢JDK中代码中可以thread的Parker的对象的park方法进行一段时间的等待。

UNSAFE_ENTRY(void,Unsafe_Park(JNIEnv*env,jobjectunsafe,jbooleanisAbsolute,jlongtime)){ HOTSPOT_THREAD_PARK_BEGIN((uintptr_t)thread->parker(),(int)isAbsolute,time);EventThreadParkevent;JavaThreadParkedStatejtps(thread,time!=0);thread->parker()->park(isAbsolute!=0,time);if(event.should_commit()){ constoopobj=thread->current_park_blocker();if(time==0){ post_thread_park_event(&event,obj,min_jlong,min_jlong);}else{ if(isAbsolute!=0){ post_thread_park_event(&event,obj,min_jlong,time);}else{ post_thread_park_event(&event,obj,time,min_jlong);}}}HOTSPOT_THREAD_PARK_END((uintptr_t)thread->parker());}UNSAFE_END

       Thread.hpp的文件中内部定义的Park对象

private:Parker_parker;public:Parker*parker(){ return&_parker;}

       ä¸‹é¢æ˜¯Os_posix.cpp中是Linux中实现的Park的park的实现方式

       é¦–先将_counter的变量通过CAS设置为0,返回就旧的值,如果之前是大于0,则说明是允许访问,不用阻塞,直接返回。

       èŽ·å–当前线程。

       åˆ¤æ–­çº¿ç¨‹æ˜¯å¦æ˜¯ä¸­æ–­ä¸­ï¼Œå¦‚果是,则直接返回,(也就是说线程处于中断状态下会忽略park,不会阻塞等待)

       åˆ¤æ–­å¦‚果传入的time参数小于0 或者 是绝对时间并且time是0,则直接返回,(上面的Unsafe调用park传入的参数是 false、0,所以不满足这种情况)

       å¦‚æžœtime大于0,则转换成绝对时间。

       åˆ›å»ºThreadBlockInVM对象,并且调用pthread_mutex_trylock获取线程互斥锁,如果没有获取到锁,则直接返回,

       åˆ¤æ–­_counter变量是否大于0,如果是,则重置_counter为0,释放线程锁,直接返回。

       è°ƒç”¨ OrderAccess::fence(); 加入内存屏障,禁止指令重排序,确保加锁和释放锁的指令的顺序。

       åˆ›å»ºOSThreadWaitState对象,

       åˆ¤æ–­time是否大于0,如果是0,则调用pthread_cond_wait进行等待,如果不是0,然后调用pthread_cond_timedwait进行时间参数为absTime的等待,

       è°ƒç”¨pthread_mutex_unlock进行释放_mutex锁,

       å†æ¬¡è°ƒç”¨OrderAccess::fence()禁止指令重排序。

//Parker::parkdecrementscountif>0,elsedoesacondvarwait.Unpark//setscountto1andsignalscondvar.Onlyonethreadeverwaits//onthecondvar.Contentionseenwhentryingtoparkimpliesthatsomeone//isunparkingyou,sodon'twait.Andspuriousreturnsarefine,sothere//isnoneedtotracknotifications.voidParker::park(boolisAbsolute,jlongtime){ //Optionalfast-pathcheck://Returnimmediatelyifapermitisavailable.//WedependonAtomic::xchg()havingfullbarriersemantics//sincewearedoingalock-freeupdateto_counter.if(Atomic::xchg(&_counter,0)>0)return;JavaThread*jt=JavaThread::current();//Optionaloptimization--avoidstatetransitionsifthere's//aninterruptpending.if(jt->is_interrupted(false)){ return;}//Next,demultiplex/decodetimeargumentsstructtimespecabsTime;if(time<0||(isAbsolute&&time==0)){ //don'twaitatallreturn;}if(time>0){ to_abstime(&absTime,time,isAbsolute,false);}//Entersafepointregion//Bewareofdeadlockssuchas.//Theper-threadParker::mutexisaclassicleaf-lock.//InparticularathreadmustneverblockontheThreads_lockwhile//holdingtheParker::mutex.Ifsafepointsarependingboththe//theThreadBlockInVM()CTORandDTORmaygrabThreads_lock.ThreadBlockInVMtbivm(jt);//Can'taccessinterruptstatenowthatweare_thread_blocked.Ifwe've//beeninterruptedsincewecheckedabovethen_counterwillbe>0.//Don'twaitifcannotgetlocksinceinterferencearisesfrom//unparking.if(pthread_mutex_trylock(_mutex)!=0){ return;}intstatus;if(_counter>0){ //nowaitneeded_counter=0;status=pthread_mutex_unlock(_mutex);assert_status(status==0,status,"invariant");//Paranoiatoensureourlockedandlock-freepathsinteract//correctlywitheachotherandJava-levelaccesses.OrderAccess::fence();return;}OSThreadWaitStateosts(jt->osthread(),false/*notObject.wait()*/);assert(_cur_index==-1,"invariant");if(time==0){ _cur_index=REL_INDEX;//arbitrarychoicewhennottimedstatus=pthread_cond_wait(&_cond[_cur_index],_mutex);assert_status(status==0MACOS_ONLY(||status==ETIMEDOUT),status,"cond_wait");}else{ _cur_index=isAbsolute?ABS_INDEX:REL_INDEX;status=pthread_cond_timedwait(&_cond[_cur_index],_mutex,&absTime);assert_status(status==0||status==ETIMEDOUT,status,"cond_timedwait");}_cur_index=-1;_counter=0;status=pthread_mutex_unlock(_mutex);assert_status(status==0,status,"invariant");//Paranoiatoensureourlockedandlock-freepathsinteract//correctlywitheachotherandJava-levelaccesses.OrderAccess::fence();Linux操作系统是如何实现pthread_cond_timedwait进行时间等待的

       pthread_cond_timedwait函数位于glibc中pthread_cond_wait.c, 可以看到是调用__pthread_cond_wait_common实现

/*See__pthread_cond_wait_common.*/int___pthread_cond_timedwait(pthread_cond_t*cond,pthread_mutex_t*mutex,conststruct__timespec*abstime){ /*Checkparametervalidity.ThisshouldalsotellthecompilerthatitcanassumethatabstimeisnotNULL.*/if(!valid_nanoseconds(abstime->tv_nsec))returnEINVAL;/*RelaxedMOissufficebecauseclockIDbitisonlymodifiedinconditioncreation.*/unsignedintflags=atomic_load_relaxed(&cond->__data.__wrefs);clockid_tclockid=(flags&__PTHREAD_COND_CLOCK_MONOTONIC_MASK)?CLOCK_MONOTONIC:CLOCK_REALTIME;return__pthread_cond_wait_common(cond,mutex,clockid,abstime);}

       ä¸‹é¢__pthread_cond_wait_common是实现通过__futex_abstimed_wait_cancelable实现时间等待

static__always_inlineint__pthread_cond_wait_common(pthread_cond_t*cond,pthread_mutex_t*mutex,clockid_tclockid,conststruct__timespec*abstime){ ''省略''`err=__futex_abstimed_wait_cancelable(cond->__data.__g_signals+g,0,clockid,abstime,private);''省略''`}

       __futex_abstimed_wait_cancelable是调用__futex_abstimed_wait_common

int__futex_abstimed_wait_cancelable(unsignedint*futex_word,unsignedintexpected,clockid_tclockid,conststruct__timespec*abstime,intprivate){ return__futex_abstimed_wait_common(futex_word,expected,clockid,abstime,private,true);}

       __futex_abstimed_wait_common下面则是通过判断平台是位或者位,调用__futex_abstimed_wait_common或者__futex_abstimed_wait_common

staticint__futex_abstimed_wait_common(unsignedint*futex_word,unsignedintexpected,clockid_tclockid,conststruct__timespec*abstime,intprivate,boolcancel){ interr;unsignedintclockbit;/*Workaroundthefactthatthekernelrejectsnegativetimeoutvaluesdespitethembeingvalid.*/if(__glibc_unlikely((abstime!=NULL)&&(abstime->tv_sec<0)))returnETIMEDOUT;if(!lll_futex_supported_clockid(clockid))returnEINVAL;clockbit=(clockid==CLOCK_REALTIME)?FUTEX_CLOCK_REALTIME:0;intop=__lll_private_flag(FUTEX_WAIT_BITSET|clockbit,private);#ifdef__ASSUME_TIME_SYSCALLSerr=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);#elseboolneed_time=abstime!=NULL&&!in_time_t_range(abstime->tv_sec);if(need_time){ err=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);if(err==-ENOSYS)err=-EOVERFLOW;}elseerr=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);#endifswitch(err){ case0:case-EAGAIN:case-EINTR:case-ETIMEDOUT:case-EINVAL:case-EOVERFLOW:/*Passedabsolutetimeoutusesbittime_ttype,butunderlyingkerneldoesnotsupportbittime_tfutexsyscalls.*/return-err;case-EFAULT:/*Musthavebeencausedbyaglibcorapplicationbug.*/case-ENOSYS:/*Musthavebeencausedbyaglibcbug.*//*Noothererrorsaredocumentedatthistime.*/default:futex_fatal_error();}}

       __futex_abstimed_wait_common是调用INTERNAL_SYSCALL_CANCEL宏定义实现

staticint__futex_abstimed_wait_common(unsignedint*futex_word,unsignedintexpected,intop,conststruct__timespec*abstime,intprivate,boolcancel){ if(cancel)returnINTERNAL_SYSCALL_CANCEL(futex_time,futex_word,op,expected,abstime,NULL/*Unused.*/,FUTEX_BITSET_MATCH_ANY);elsereturnINTERNAL_SYSCALL_CALL(futex_time,futex_word,op,expected,abstime,NULL/*Ununsed.*/,FUTEX_BITSET_MATCH_ANY);}

       ç³»ç»Ÿè°ƒç”¨çš„的宏定义

/***Blockscurrentthread,returningwhenabalancing*{ @codeunpark}occurs,orabalancing{ @codeunpark}has*alreadyoccurred,orthethreadisinterrupted,or,ifnot*absoluteandtimeisnotzero,thegiventimenanosecondshave*elapsed,orifabsolute,thegivendeadlineinmilliseconds*sinceEpochhaspassed,orspuriously(i.e.,returningforno*"reason").Note:ThisoperationisintheUnsafeclassonly*because{ @codeunpark}is,soitwouldbestrangetoplaceit*elsewhere.*/publicnativevoidpark(booleanisAbsolute,longtime);0总结

       ä¸»è¦å¯¹LockSupport的park等待实现的底层实现的浅析,针对于Linux的系统调用还没有找到源码,后续会继续跟踪,希望有读者知道的满帆可以告知下,谢谢。

链接:/post/

深入探秘高性能并发:C++如何在Linux巧妙应用Futex实现线程锁同步(ob_latch.cpp篇)大篇幅(3万字)

       通过实例学习C++的Futex应用,理解线程锁同步在OceanBase 4.0源码中的巧妙使用

       这篇文章详细介绍了如何在Linux环境下,利用C++的Futex实现线程锁同步,以开源项目ob_latch.cpp为例,探讨了自旋锁、站长工具整站源码互斥锁和等待队列的实现和优缺点。

       1. 自旋锁分析:通过low_try_lockA,自旋次数由max_spin_cnt控制,避免CPU资源浪费。

       2. 互斥锁-ObLatchMutex:提供try_lock, lock, wait三种加锁方式,分别对应不同的场景和策略。

       3. ObLatchWaitQueue:管理等待队列,确保公平调度,如wait阻塞锁的使用和唤醒机制。

       4. 锁的解锁逻辑:如ObLatchMutex的unlock,通过原子操作移除或减少锁的持有计数,必要时唤醒等待队列。

       5. 高级锁封装:如ObLatchWGuard等RAII类,自动管理锁的生命周期,确保资源安全。

       通过以上组件的组合,开发者可以灵活设计线程同步机制,保证多线程环境下资源访问的正确性和效率。

       如果你在项目中设计线程锁,可以根据这些原理和实例进行调整和优化。

实习面试总结 -> fork与🔒

       在讨论fork与互斥锁的继承问题时,我们可以直接回答:在使用fork创建子进程后,子进程将继承父进程的互斥锁状态。这是灵犀外卖源码基于互斥锁在用户层面被视为一个对象的特性,系统并不会强制在获取锁后再执行线程函数。然而,需要注意的是,文件锁(flock)是一个特殊的情况。如果父进程持有已加锁的互斥锁,子进程同样会继承这个加锁状态。但是,当父进程的锁解锁时,子进程的锁并不会自动解锁,这是文件锁与其他锁的主要区别。理解这一点需要深入理解task_struct,这是进程管理的核心结构,其中包含了多个成员,如struct files_struct* files,用于保存进程已打开文件的信息。因此,继承问题的关键在于正确理解不同类型的锁和它们在进程间共享的方式。

       关于写事件,fork不会导致写事件的复制,因为fork实际上复制了整个task_struct,而不仅仅是指针。打开的文件和相关资源在子进程和父进程之间共享,但是复制操作在内存管理层面不会被复制。子进程可以直接操作父进程分配的内存,但不会自动继承父进程对文件的读写操作。这意味着在父子进程中读取文件时,内容会保持一致,除非有并发写操作或文件锁定机制的介入。

       文件锁的liteos 内核源码继承与互斥锁的继承有所不同,因为文件锁关联的是文件表中的特定文件,而不仅仅是进程。这意味着在父子进程间共享的是一份文件锁的引用,而不是锁的实例。因此,当父进程和子进程都打开同一个文件并分别获得锁时,他们实际上共享同一个锁对象,而不是复制这个对象。这与某些情况下会发生copy on write的现象有所区别。copy on write意味着在多个进程间共享资源时,直到实际修改发生才在需要的地方创建副本。在文件锁的情况下,因为锁对象是唯一的,所以不会发生这种复制。

       在多线程环境下,当父进程使用fork创建子进程时,子进程只会启动父进程当前正在执行的线程,其他线程不会被复制。这意味着如果在主线程中上锁,然后创建一个新线程,子进程将继承这个锁的状态。然而,如果在主线程中解锁,这个解锁操作不会被子进程继承,导致在子进程中再次尝试上锁时可能出现死锁。为了解决这个问题,pthread库提供了一个函数pthread_atfork,它允许开发者在多线程环境中使用fork时处理死锁问题。

       对于文件锁的源码资本 春细节和底层实现,如futex机制和pthread_atfork的使用,深入理解需要查看相关源代码和文档。futex提供了一种高效的方式来实现用户态锁,而pthread_atfork则提供了一种标准化的方法来处理在多线程环境下的fork操作,避免死锁。这些技术对于系统和并发编程的实现至关重要,但理解其内部工作原理需要详细阅读底层代码和相关技术文档。

深入解析 go 互斥锁 mutex 源码

       互斥锁是并发控制的基石,用于避免多线程竞争带来的数据不一致性问题。以加法运算为例,若不使用互斥锁,多个线程同时执行加法操作可能导致数据覆盖,结果不准确。互斥锁(Mutex)确保在同一时刻只有一个线程访问共享资源。

       在互斥锁的源码解析中,我们关注几个核心问题:饥饿问题、性能优化、锁的创建与操作。

       互斥锁通常会经历几代优化,以提升性能与公平性。例如,当一个线程在等待获取锁时,系统可能选择将锁直接分配给等待时间最长的线程(饥饿模式),以确保所有线程都有机会访问共享资源。在正常模式下,锁的分配遵循先入先出的原则,以提升性能。这些模式的选择和切换依赖于互斥锁内部的状态。

       互斥锁的ssm文化源码实现涉及位运算,如位与(&)、位或(|)、位异或(^)等操作。这些位操作用于管理锁的状态,如判断锁是否被持有、锁是否处于饥饿状态等。

       在使用互斥锁时,需要注意几个常见错误:锁重入、锁拷贝和死锁。锁重入允许同一线程多次获取同一锁,无需阻塞。锁拷贝则涉及锁的复制,需确保复制时不破坏锁的状态。死锁是由于线程间循环等待资源而导致的僵局,需通过合理设计避免。

       在并发编程中,正确使用互斥锁至关重要,需遵循“谁申请,谁释放”的原则,避免锁的不当释放导致的不可预期行为。对于更高级的锁机制,如自旋锁、阻塞锁和排他锁,它们在并发控制中发挥着不同的作用,提供了不同程度的性能优化和安全保证。

       此外,信号量(semaphore)是一种常见的同步工具,用于协调并发操作。它提供了类似于互斥锁的功能,但允许更细粒度的控制,如允许多个读锁而只允许一个写锁。信号量的实现通常依赖于系统调用,如Linux的futex,或在Go中使用专门的同步库。

       总体而言,互斥锁是并发编程中不可或缺的工具,正确理解和使用它们能够有效管理并发问题,确保程序的正确性和稳定性。

什么是futex?

       一、解锁神秘的futex:用户空间的同步神器

       Futex,即Fast Userspace muTEX,是Linux内核中一项强大的用户空间同步工具,由Rusty Russell、Hubertus Franke和Mathew Kirkwood在2.5.7版本引入。它并非单纯的互斥锁,而是一个通用的同步机制,允许在用户空间实现互斥锁、读写锁和条件变量等复杂同步操作,无需频繁地穿越内核空间。

       核心是用户空间的-bit futex word,它与内核中的等待队列协同工作。在无竞争情况下,获取和释放锁的性能极高,只需通过原子操作即可。竞争激烈时,线程无法立即获取,会陷入内核,但只有在锁持有者释放时检测到竞争,才会唤醒等待队列中的线程。

       二、深入接口:解锁futex的密码

       Futex提供了丰富的接口函数,如FUTEX_WAIT、FUTEX_WAKE等,每个操作码都对应着复杂的参数管理。例如,FUTEX_WAIT等待futex word的特定值,FUTEX_WAKE则用于唤醒等待队列中的线程。这些接口允许高级同步操作在用户空间精细控制。

       三、内核中的组织:如何构建等待队列

       Futex的数据结构巧妙地结合了用户空间的futex word和内核的等待队列。内核通过哈希表管理这些队列,保证了高效和一致性。每对futex word和等待队列都通过哈希值关联起来,确保同步操作的准确执行。

       四、futex_wait的幕后揭秘

       当调用futex_wait时,首先会检查timeout,设置计时器以防止无限阻塞。接着,通过计算三元组确定hash key,确保任务正确插入队列。在插入前,还需验证期望值是否变化,确保同步的正确性。rt线程和cfs任务按照特定策略排队,优先级高的先执行。

       五、futex_wake:唤醒的优雅节奏

       futex_wake的流程相对简单,涉及找到对应futex word的等待队列,通过比特匹配唤醒指定线程,控制唤醒数量,且支持用户自定义唤醒策略。唤醒队列的使用使得一个操作可以同时影响多个等待任务。

       六、requeue:从复杂到简化

       Requeue操作是为了优化等待-通知机制,一次操作即可完成多个同步步骤,避免了传统方式下的两次系统调用。它涉及两个futex,通过hash表操作和比特匹配来实现任务的移动和唤醒。

       七、优先级继承:解决优先级翻转问题

       PI(优先级继承)futex通过rt mutex解决优先级翻转,通过临时提升优先级,确保任务按预期顺序执行。关键在于维护任务与锁的优先级关系,形成PI chain来确保同步的正确性。

       八、rt mutex:PI futex的执行器

       rt mutex是PI futex背后的力量,它通过代理任务和锁之间的关系,实现了优先级继承协议。rt mutex的结构和操作确保了系统中同步的稳定性和性能。

       九、futex与rt mutex的连接

       在用户空间,futex通过FUTEX_LOCK_PI和FUTEX_UNLOCK_PI与rt mutex交互,代理上锁和解锁操作,同时管理PI状态。这两个机制在用户空间同步中发挥着至关重要的作用。

       十、PI futex的逻辑流程

       PI futex的核心逻辑包括在竞争失败时进入内核,创建和管理rt mutex,以及根据PI状态调整任务优先级。解锁过程则涉及到rt mutex的释放和优先级恢复。

       十一、总结:解锁futex的全貌

       Futex是用户空间同步的基石,它以高效和灵活的方式处理同步任务。本文只是触及了其冰山一角,rt mutex的深入探索将在后续内容中展开。

       

参考资料:

Linux内核源代码5..版本和相关文档

Android 属性系统原理,检测与定制源码反检测

       本文基于看雪论坛精华内容,由作者飞翔的猫咪探讨Android 属性系统的深层次理解,包括检测与反检测策略。这些属性在Android系统中扮演着设备信息和运行时配置的关键角色,对于改机和设备指纹收集至关重要。

       Android属性系统的基础构建在键值对上,每个属性都有类型(如string、int、bool),并由SELinux上下文保护。初始化和修改属性的过程涉及init进程通过mmap映射/dev/__properties__目录下的文件到进程的虚拟内存区域,以共享内存方式实现进程间通信。只有init进程能创建和修改属性,其他进程通过socket与init通信,而普通app受限于权限,无法直接操作。

       属性主要分为ro(只读)、persist(持久化)、ctl(控制)和selinux.restorecon_recursive,各有不同的处理逻辑。为了提升效率,Android在文件格式设计上考虑了频繁获取的场景,并使用属性缓存机制,这对改机技术构成挑战。

       属性同步通过包装futex系统调用实现,getprop工具则用于获取属性值,提供参数选项以获取上下文和类型信息。属性的核心API在bionic libc的头文件中定义,需通过特定宏定义来正确包含。

       系统开发者倾向于通过预定义的接口使用属性,而非直接调用,如__system_property_set_value和__system_property_find等,它们分别用于设置和查找属性。设置权限由selinux策略通过set_prop宏管理,如system_app域可设置特定属性。

       属性系统通过__system_property_read_callback和缓存机制提高效率,如CachedProperty.h文件中的函数。遍历属性和等待属性变化的功能分别由system_property_foreach和WaitForProperty实现。部分接口已废弃,但仍在部分框架代码中使用。

       总结来说,属性系统的核心是init进程管理和响应其他进程的通信请求,而普通app在权限和策略的限制下,操作受限。理解这些原理对于深入研究和安全定制Android系统至关重要。

搜索关键词:投影互动系统源码