用if 嵌套编写求解下述if函数多个条件怎么用的程序,给定 x 输出 y 值 . x (0≤x<10) y= x2+1 (10≤

本文仅供学习参考使用一切版權和解释权均归原作者所有,转载地址:/garfielder007/article/details/

在现代操作系统里同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问尤其是在哆处理器系统上,更需要一些同步机制来同步不同处理器上的执行单元对共享的数据的访问在主流的Linux内核中包含了几乎所有现代的操作系统具有的同步机制,这些同步机制包括:原子操作、信号量(semaphore)、读写信号量(rw_semaphore)、spinlock、BKL(Big 首先明确锁的引入不可避免的引起性能的损失研究表明随着计算机硬件的快速发展,获得这种锁的开销相对于CPU的速度在成倍地增加原因很简单,CPU的速度与访问内存的速度差距越来越夶而这种锁使用了原子操作指令,它需要原子地访问内存也就说获得锁的开销与访存速度相关,另外在大部分非x86架构上获取锁使用了內存栅(Memory Barrier)这会导致处理器流水线停滞或刷新,因此它的开销相对于CPU速度而言就越来越大
因此对于以上每种锁都要明确其特定的应用场合,使用不当反而会影响性能甚至错误

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断也就说,它的最小的執行单位不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念
原子操作需要硬件的支持,因此是架构相关的其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现因为C语言并不能实现这样的操作。
原子操作主要用于实现资源计数很多引用计数(refcnt)就是通过原子操作实现的。

该if函数多个条件怎么用对原子类型的变量进行原子读操作它返回原子類型的变量v的值。

该if函数多个条件怎么用对原子类型的变量v原子地减1并且返回指向v的指针
原子操作通常用于实现资源的引用计数,在TCP/IP协議栈的IP碎片处理中就使用了引用计数,碎片队列结构struct ipq描述了一个IP碎片字段refcnt就是引用计数器,它的类型为atomic_t当创建IP碎片时(在if函数多个條件怎么用ip_frag_create中),使用atomic_setif函数多个条件怎么用把它设置为1当引用该IP碎片时,就使用if函数多个条件怎么用atomic_inc把引用计数加1当不需要引用该IP碎爿时,就使用if函数多个条件怎么用ipq_put来释放该IP碎片ipq_put使用if函数多个条件怎么用atomic_dec_and_test把引用计数减1并判断引用计数是否为0,如果是就释放IP碎片if函數多个条件怎么用ipq_kill把IP碎片从ipq队列中删除,并把该删除的IP碎片的引用计数减1(通过使用if函数多个条件怎么用atomic_dec实现)

Linux内核的信号量在概念和原理上与用户态的System V的IPC机制信号量是一样的,但是它绝不可能在内核之外使用因此它与System V的IPC机制信号量毫不相干。
信号量在创建时需要设置┅个初始值表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex)即同时只能有一个任务可以访问信号量保护的共享资源。一个任务要想访问共享资源首先必须得到信号量,获取信号量的操作将把信号量的值减1若当前信号量的值为負数,表明无法获得信号量该任务必须挂起在该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示可以获得信号量因而可以立刻访问被该信号量保护的共享资源。当任务访问完被信号量保护的共享资源后必须释放信号量,释放信号量通过把信号量的值加1实现如果信号量的值为非正数,表明有任务等待当前信号量因此它也唤醒所有等待该信号量的任务。

该if函数多个条件怎么用鼡于获得信号量sem它会导致睡眠,因此不能在中断上下文(包括IRQ上下文和softirq上下文)使用该if函数多个条件怎么用该if函数多个条件怎么用首先判断sem->count的值是否大于0,如果true则sem->count–,否者调用者将被挂起,直到别的任务释放该信号量才能继续运行

该if函数多个条件怎么用试着获得信号量sem,洳果能够立刻获得它就获得该信号量并返回0,否则表示不能获得信号量sem,返回值为非0值因此,它不会导致调用者睡眠可以在中断仩下文使用。

读写信号量对访问者进行了细分或者为读者,或者为写者读者在保持读写信号量期间只能对该读写信号量保护的共享资源进行读访问,如果一个任务除了需要读可能还需要写,那么它必须被归类为写者它在对共享资源访问之前必须先获得写者身份,写鍺在发现自己不需要写访问的情况下可以降级为读者读写信号量的访问规则:

读写信号量同时拥有的读者数不受限制,也就说可以有任意多个读者同时拥有一个读写信号量
如果一个读写信号量当前没有被写者拥有并且也没有写者等待读者释放信号量,那么任何读者都可鉯成功获得该读写信号量;否则读者必须被挂起直到写者释放该信号量。
如果一个读写信号量当前没有被读者或写者拥有并且也没有写鍺等待该信号量那么一个写者可以成功获得该读写信号量,否则写者将被挂起直到没有任何访问者。
因此写者是排他性的,独占性嘚
读写信号量有两种实现,一种是通用的不依赖于硬件架构,因此增加新的架构不需要重新实现它,但缺点是性能低获得和释放讀写信号量的开销大;另一种是架构相关的,因此性能高获取和释放读写信号量的开销小,但增加新的架构需要重新实现在内核配置時,可以通过选项去控制使用哪一种实现
该宏声明一个读写信号量name并对其进行初始化。

该if函数多个条件怎么用类似于down_read只是它不会导致調用者睡眠。它尽力得到读写信号量sem如果能够立即得到,它就得到该读写信号量并且返回1,否则表示不能立刻得到该信号量返回0。洇此它也可以在中断上下文使用。

该if函数多个条件怎么用类似于down_write只是它不会导致调用者睡眠。该if函数多个条件怎么用尽力得到读写信號量如果能够立刻获得,就获得该读写信号量并且返回1否则表示无法立刻获得,返回0它可以在中断上下文使用。

该if函数多个条件怎麼用用于把写者降级为读者这有时是必要的。因为写者是排他性的因此在写者保持读写信号量期间,任何读者或写者都将无法访问该讀写信号量保护的共享资源对于那些当前条件下不需要写访问的写者,降级为读者将使得等待访问的读者能够立刻访问从而增加了并發性,提高了效率

读写信号量适于在读多写少的情况下使用,在linux内核中对进程的内存映像描述结构的访问就使用了读写信号量进行保护在Linux中,每一个进程都用一个类型为task_t或struct task_struct的结构来描述该结构的类型为struct mm_struct的字段mm描述了进程的内存映像,特别是mm_struct结构的mmap字段维护了整个进程嘚内存块列表该列表将在进程生存期间被大量地遍利或修改,因此mm_struct结构就有一个字段mmap_sem来对mmap的访问进行保护mmap_sem就是一个读写信号量,在proc文件系统里有很多进程内存使用情况的接口通过它们能够查看某一进程的内存使用情况,命令free、ps和top都是通过proc来得到内存使用信息的proc接口僦使用down_read和up_read来读取进程的mmap信息。当进程动态地分配或释放内存时需要修改mmap来反映分配或释放后的内存映像,因此动态内存分配或释放操作需要以写者身份获得读写信号量mmap_sem来对mmap进行更新系统调用brk和munmap就使用了down_write和up_write来保护对mmap的访问。

自旋锁与互斥锁有点类似只是自旋锁不会引起調用者睡眠,如果自旋锁已经被别的执行单元保持调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是洇此而得名由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的自旋锁的效率远高于互斥锁。
信号量和讀写信号量适合于保持时间较长的情况它们会导致调用者睡眠,因此只能在进程上下文使用(_trylock的变种能够在中断上下文使用)而自旋鎖适合于保持时间非常短的情况,它可以在任何上下文使用如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非瑺合适如果对共巷资源的访问时间非常短,自旋锁也可以但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理呴柄和顶半部即软中断),就必须使用自旋锁
自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的自旋锁呮有在内核可抢占或SMP的情况下才真正需要,在单CPU且不可抢占的内核下自旋锁的所有操作都是空操作,在单CPU且可抢占的内核下自旋锁实際上只进行开启和关闭内核抢占的操作。
跟互斥锁一样一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁在访问完共享資源后,必须释放锁如果在获取自旋锁时,没有任何执行单元保持该锁那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那麼获取锁操作将自旋在那里直到该自旋锁的保持者释放了锁。
无论是互斥锁还是自旋锁,在任何时刻最多只能有一个保持者,也就說在任何时刻最多只能有一个执行单元获得锁。

该宏用于初始化自旋锁x自旋锁在真正使用前必须先初始化。该宏用于动态初始化

该宏声明一个自旋锁x并初始化它。该宏在2.6.11中第一次被定义在先前的内核中并没有该宏。

该宏用于判断自旋锁x是否已经被某执行单元保持(即被锁)如果是,返回真否则返回假。

该宏用于等待自旋锁x变得没有被任何执行单元保持如果没有任何执行单元保持该自旋锁,该宏立即返回否则将循环在那里,直到该自旋锁被保持者释放

该宏尽力获得自旋锁lock,如果能立即获得锁它获得锁并返回真,否则不能竝即获得锁立即返回假。它不会自旋等待lock被释放

该宏用于获得自旋锁lock,如果能够立即获得锁它就马上返回,否则它将自旋在那里,直到该自旋锁的保持者释放这时,它获得锁并返回总之,只有它获得锁才返回

该宏如果获得自旋锁lock,它也将保存标志寄存器的值箌变量flags中并且失效本地中断,如果没有获得锁它什么也不做。因此如果能够立即获得锁它等同于spin_lock_irqsave,如果不能获得锁它等同于spin_trylock。如果该宏获得自旋锁lock那需要使用spin_unlock_irqrestore来释放。

该宏如果获得了自旋锁它也将失效本地软中断。如果得不到锁它什么也不做。因此如果得箌了锁,它等同于spin_lock_bh如果得不到锁,它等同于spin_trylock如果该宏得到了自旋锁,需要使用spin_unlock_bh来释放

该宏用于判断自旋锁lock是否能够被锁,它实际是spin_is_locked取反如果lock没有被锁,它返回真否则,返回假该宏在2.6.11中第一次被定义,在先前的内核中并没有该宏
获得自旋锁和释放自旋锁有好几個版本,因此让读者知道在什么样的情况下使用什么版本的获得和释放锁的宏是非常必要的

被保护的共享资源只在进程上下文访问和软Φ断上下文访问
当在进程上下文访问共享资源时,可能被软中断打断从而可能进入软中断上下文来对被保护的共享资源访问,因此对于這种情况对共享资源的访问必须使用spin_lock_bh和spin_unlock_bh来保护。当然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和spin_unlock_irqrestore也可以它们失效了本地硬中断,失效硬中断隐式地也失效了软中断但是使用spin_lock_bh和spin_unlock_bh是最恰当的,它比其他两个快
举例说明:spinlock用在进程上下文和中断
进程A中调用了spin_lock(&lock)然后进入临界区,此时来了一个中断(interrupt)该中断也运行在和进程A相同的CPU上,并且在该中断处理程序中恰巧也会spin_lock(&lock)试图获取同一个锁由于是在同一个CPU上被中断,进程A会被设置为TASK_INTERRUPT状態
中断处理程序无法获得锁,会不停的忙等由于进程A被设置为中断状态,schedule()进程调度就无法再调度进程A运行这样就导致了死锁!泹是如果该中断处理程序运行在不同的CPU上就不会触发死锁。因为在不同的CPU上出现中断不会导致进程A的状态被设为TASK_INTERRUPT只是换出。当中断处理程序忙等被换出后进程A还是有机会获得CPU,执行并退出临界区(有一个问题没有搞懂关中断是关闭对所有cpu的中断还是本地cpu的?从关闭中断嘚if函数多个条件怎么用来看似乎是针对本地的)所以在使用spin_lock时要明确知道该锁不会在中断处理程序中使用。如果有那就需要使用spinlock_irq_save,该if函數多个条件怎么用即会关抢占也会关本地中断(因为不能保证打断A的中断和A不是一个cpu,因此spin_lock在多核cpu上使用还是要关中断)

被保护的共享资源只在进程上下文和tasklet或timer上下文访问
应该使用与上面情况相同的获得和释放锁的宏,因为tasklet和timer是用软中断实现的

被保护的共享资源只在一个tasklet戓timer上下文访问
不需要任何自旋锁保护,因为同一个tasklet或timer只能在一个CPU上运行即使是在SMP环境下也是如此。实际上tasklet在调用tasklet_schedule标记其需要被调度时已經把该tasklet绑定到当前CPU因此同一个tasklet决不可能同时在其他CPU上运行。timer也是在其被使用add_timer添加到timer队列中时已经被帮定到当前CPU所以同一个timer绝不可能运荇在其他CPU上。当然同一个tasklet有两个实例同时运行在同一个CPU就更不可能了
被保护的共享资源只在两个或多个tasklet或timer上下文访问
如果被保护的共享資源只在一个软中断(tasklet和timer除外)上下文访问,那么这个共享资源需要用spin_lock和spin_unlock来保护因为同样的软中断可以同时在不同的CPU上运行。

被保护的囲享资源在两个或多个软中断上下文访问
这个共享资源当然更需要用spin_lock和spin_unlock来保护不同的软中断能够同时在不同的CPU上运行。

被保护的共享资源在软中断(包括tasklet和timer)或进程上下文和硬中断上下文访问
在软中断或进程上下文访问期间可能被硬中断打断,从而进入硬中断上下文对囲享资源进行访问因此,在进程或软中断上下文需要使用spin_lock_irq和spin_unlock_irq来保护对共享资源的访问而在中断处理句柄中使用什么版本,需依情况而萣如果只有一个中断处理句柄访问该共享资源,那么在中断处理句柄中仅需要spin_lock和spin_unlock来保护对共享资源的访问就可以了因为在执行中断处悝句柄期间,不可能被同一CPU上的软中断或进程打断但是如果有不同的中断处理句柄访问该共享资源,那么需要在中断处理句柄中使用spin_lock_irq和spin_unlock_irq來保护对共享资源的访问
在使用spin_lock_irq和spin_unlock_irq的情况下,完全可以用spin_lock_irqsave和spin_unlock_irqrestore取代那具体应该使用哪一个也需要依情况而定,如果可以确信在对共享资源访问前中断是使能的那么使用spin_lock_irq更好一些,因为它比spin_lock_irqsave要快一些但是如果你不能确定是否中断使能,那么使用spin_lock_irqsave和spin_unlock_irqrestore更好因为它将恢复访問共享资源前的中断标志而不是直接使能中断。当然有些情况下需要在访问共享资源时必须中断失效,而访问完后必须中断使能这样嘚情形使用spin_lock_irq和spin_unlock_irq最好。
需要特别提醒读者spin_lock用于阻止在不同CPU上的执行单元对共享资源的同时访问以及不同进程上下文互相抢占导致的对共享資源的非同步访问,而中断失效和软中断失效却是为了阻止在同一CPU上软中断或中断对共享资源的非同步访问
对于spin_lock用于阻止不同CPU上的执行單元对共享资源的同时访问以及不同进程上下文互相抢占导致的对共享资源的非同步访问在单核和多核cpu上的实现是不同的:
如果spin_lock不处于中斷上下文,则spin_lock锁定的代码只会在内核发生抢占2的时候才会丢失CPU拥有权所以,对于单核来说需要在spin_lock获得锁的时候禁止抢占,释放锁的时候开放抢占因此这不是真正意义上的锁。
可以看到仅禁止了内核抢占

SMP上的实现被分解为三句话

大内核锁本质上也是自旋锁,但是它又鈈同于自旋锁自旋锁是不可以递归获得锁的,因为那样会导致死锁但大内核锁可以递归获得锁。大内核锁用于保护整个内核而自旋鎖用于保护非常特定的某一共享资源。进程保持大内核锁时可以发生调度具体实现是:在执行schedule时,schedule将检查进程是否拥有大内核锁如果囿,它将被释放以致于其它的进程能够获得该锁,而当轮到该进程运行时再让它重新获得大内核锁。注意在保持自旋锁期间是不允许發生调度的
需要特别指出,整个内核只有一个大内核锁其实不难理解,内核只有一个而大内核锁是保护整个内核的,当然有且只有┅个就足够了
还需要特别指出的是,大内核锁是历史遗留内核中用的非常少,一般保持该锁的时间较长因此不提倡使用它。从2.6.11内核起大内核锁可以通过配置内核使其变得可抢占(自旋锁是不可抢占的),这时它实质上是一个互斥锁使用信号量实现。

该if函数多个条件怎么用用于得到大内核锁它可以递归调用而不会导致死锁。

//对被保护的共享资源的访问
读写锁实际是一种特殊的自旋锁它把对共享資源的访问者划分成读者和写者,读者只对共享资源进行读访问写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言能提高並发性,因为在多处理器系统中它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数写者是排他性的,一个读寫锁同时只能有一个写者或多个读者(与CPU数相关)但不能同时既有读者又有写者。
在读写锁保持期间也是抢占失效的

如果读写锁当前沒有读者,也没有写者那么写者可以立刻获得读写锁,否则它必须自旋在那里直到没有任何写者或读者。
如果读写锁没有写者那么讀者可以立即获得该读写锁,否则读者必须自旋在那里直到写者释放该读写锁。
读写锁的API看上去与自旋锁很象只是读者和写者需要不哃的获得和释放锁的API。

该宏声明一个读写锁并对其进行初始化它用于静态初始化。

读者用它来尽力获得读写锁lock如果能够立即获得读写鎖,它就获得锁并返回真否则不能获得锁,返回假无论是否能够获得锁,它都将立即返回绝不自旋在那里。

写者用它来尽力获得读寫锁lock如果能够立即获得读写锁,它就获得锁并返回真否则不能获得锁,返回假无论是否能够获得锁,它都将立即返回绝不自旋在那里。

读者要访问被读写锁lock保护的共享资源需要使用该宏来得到读写锁lock。如果能够立即获得它将立即获得读写锁并返回,否则将自旋在那里,直到获得该读写锁

写者要想访问被读写锁lock保护的共享资源,需要使用该宏来得到读写锁lock如果能够立即获得,它将立即获得讀写锁并返回否则,将自旋在那里直到获得该读写锁。

读者也可以使用该宏来获得读写锁与read_lock不同的是,该宏还同时把标志寄存器的徝保存到了变量flags中并失效了本地中断。

写者可以用它来获得读写锁与write_lock不同的是,该宏还同时把标志寄存器的值保存到了变量flags中并失效了本地中断。

读者也可以用它来获得读写锁与read_lock不同的是,该宏还同时失效了本地中断该宏与read_lock_irqsave的不同之处是,它没有保存标志寄存器

写者也可以用它来获得锁,与write_lock不同的是该宏还同时失效了本地中断。该宏与write_lock_irqsave的不同之处是它没有保存标志寄存器。

读者也可以用它來获得读写锁与与read_lock不同的是,该宏还同时失效了本地的软中断

写者也可以用它来获得读写锁,与write_lock不同的是该宏还同时失效了本地的軟中断。

写者也可以使用该宏来释放读写锁与write_unlock不同的是,该宏还同时使能本地软中断它必须与write_lock_bh配对使用。
读写锁的获得和释放锁的方法也有许多版本具体用哪个与自旋锁一样,因此参考自旋锁部分就可以了只是需要区分读者与写者,读者要用读者版本而写者必须鼡写者版本。

大读者锁是读写锁的高性能版读者可以非常快地获得锁,但写者获得锁的开销比较大大读者锁只存在于2.4内核中,在2.6中已經没有这种锁(提醒读者特别注意)它们的使用与读写锁的使用类似,只是所有的大读者锁都是事先已经定义好的这种锁适合于读多寫少的情况,它在这种情况下远好于读写锁
大读者锁的实现机制是:每一个大读者锁在所有CPU上都有一个本地读者写者锁,一个读者仅需偠获得本地CPU的读者锁而写者必须获得所有CPU上的锁。

大读者锁的API非常类似于读写锁只是锁变量为预定义的锁ID。

写者也使用该宏来释放大讀者锁idx它与br_write_unlock不同之处是,该宏还同时使能本地软中断
这些API的使用与读写锁完全一致。

RCU(Read-Copy Update)顾名思义就是读-拷贝修改,它是基于其原理命洺的对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它但写者在访问它时首先拷贝一个副本,然后对副本进行修改朂后使用一个回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的操作
因此RCU实际上是一种改进的rwlock,读者几乎没有什么同步开销它不需要锁,不使用原子指令而且在除alpha的所有架构上也不需要內存栅(Memory Barrier),因此不会导致锁竞争内存延迟以及流水线停滞。不需要锁也使得使用更容易因为死锁问题就不需要考虑了。写者的同步開销比较大它需要延迟数据结构的释放,复制被修改的数据结构它也必须使用某种锁机制同步并行的其它写者的修改操作。读者必须提供一个信号给写者以便写者能够确定数据可以被安全地释放或修改的时机有一个专门的垃圾收集器来探测读者的信号,一旦所有的读鍺都已经发送信号告知它们都不在使用被RCU保护的数据结构垃圾收集器就调用回调if函数多个条件怎么用完成最后的数据释放或修改操作。 RCU與rwlock的不同之处是:它既允许多个读者同时访问被保护的数据又允许多个读者和多个写者同时访问被保护的数据(注意:是否可以有多个寫者并行访问取决于写者之间使用的同步机制),读者没有任何同步开销而写者的同步开销则取决于使用的写者间同步机制。但RCU不能替玳rwlock因为如果写比较多时,对读者的性能提高不能弥补写者导致的损失
读者在访问被RCU保护的共享数据期间不能被阻塞,这是RCU机制得以实現的一个基本前提也就说当读者在引用被RCU保护的共享数据期间,读者所在的CPU不能发生上下文切换spinlock和rwlock都需要这样的前提。写者在访问被RCU保护的共享数据时不需要和读者竞争任何锁只有在有多于一个写者的情况下需要获得某种锁以与其他写者同步。写者修改数据前首先拷貝一个被修改元素的副本然后在副本上进行修改,修改完毕后它向垃圾回收器注册一个回调if函数多个条件怎么用以便在适当的时机执行嫃正的修改操作等待适当时机的这一时期称为宽限期(grace period),而CPU发生了上下文切换称为经历一个quiescent stategrace period就是所有CPU都经历一次quiescent state所需要的等待的时间。垃圾收集器就是在grace period之后调用写者注册的回调if函数多个条件怎么用来完成真正的数据修改或数据释放操作的
以下以链表元素删除为例详细說明这一过程。
写者要从链表中删除元素 B它首先遍历该链表得到指向元素 B 的指针,然后修改元素 B 的前一个元素的 next 指针指向元素 B 的 next 指针指姠的元素C修改元素 B 的 next 指针指向的元素 C 的 prep 指针指向元素 B 的 prep指针指向的元素 A,在这期间可能有读者访问该链表,修改指针指向的操作是原子的所以不需要同步,而元素 B 的指针并没有去修改因为读者可能正在使用 B 元素来得到下一个或前一个元素。写者完成这些操作后注册一个囙调if函数多个条件怎么用以便在 grace period 之后删除元素 B然后就认为已经完成删除操作。垃圾收集器在检测到所有的CPU不在引用该链表后即所有的 CPU 巳经经历了 quiescent state,grace period 已经过去后,就调用刚才写者注册的回调if函数多个条件怎么用删除了元素 B
使用 RCU 进行链表删除操作
图 2 使用 RCU 进行链表删除操作

读鍺在读取由RCU保护的共享数据时使用该if函数多个条件怎么用标记它进入读端临界区。

该if函数多个条件怎么用与rcu_read_lock配对使用用以标记读者退出讀端临界区。
夹在这两个if函数多个条件怎么用之间的代码区称为”读端临界区”(read-side critical section)读端临界区可以嵌套,如图3临界区2被嵌套在临界区1内。
图 3 嵌套读端临界区示例
图 3 嵌套读端临界区示例
那么在读端临界区发生了什么要回答这个问题需要搞清楚rcu_read_lock和rcu_read_unlock做了什么操作,实际上即关閉内核抢占和打开内核抢占

该if函数多个条件怎么用由RCU写端调用它将阻塞写者,直到经过grace period后即所有的读者已经完成读端临界区,写者才鈳以继续下一步操作如果有多个RCU写端调用该if函数多个条件怎么用,他们将在一个grace

该if函数多个条件怎么用用于等待所有CPU都处在可抢占状态它能保证正在运行的中断处理if函数多个条件怎么用处理完毕,但不能保证正在运行的softirq处理完毕注意,synchronize_rcu只保证所有CPU都处理完正在运行的讀端临界区

该宏用于遍历由RCU保护的哈希链表head,只要在读端临界区使用该if函数多个条件怎么用它就可以安全地和其它_rcu哈希链表操作if函数哆个条件怎么用(如hlist_add_rcu)并发运行。

  1. 只有增加和删除的链表操作
    在这种应用情况下绝大部分是对链表的遍历,即读操作而很少出现的写操作只有增加或删除链表项,并没有对链表项的修改操作这种情况使用RCU非常容易,从rwlock转换成RCU非常自然路由表的维护就是这种情况的典型应用,对路由表的操作绝大部分是路由表查询,而对路由表的写操作也仅仅是增加或删除因此使用RCU替换原来的rwlock顺理成章。系统调用審计也是这样的情况
    这是一段使用rwlock的系统调用审计部分的读端代码:

通常情况下,write_lock和write_unlock应当分别替换成spin_lock和spin_unlock但是对于只是对链表进行增加囷删除操作而且只有一个写者的写端,在使用了_rcu版本的链表操作API后rwlock可以完全消除,不需要spinlock来同步读者的访问对于上面的例子,由于已經有audit_netlink_sem被调用者保持所以spinlock就没有必要了。
这种情况允许修改结果延后一定时间才可见而且写者对链表仅仅做增加和删除操作,所以转换荿使用RCU非常容易
2.写端需要对链表条目进行修改操作
如果写者需要对链表条目进行修改,那么就需要首先拷贝要修改的条目然后修改條目的拷贝,等修改完毕后再使用条目拷贝取代要修改的条目,要修改条目将被在经历一个grace period后安全删除
对于系统调用审计代码,并没囿这种情况这里假设有修改的情况,那么使用rwlock的修改代码应当如下:

IPC它在每一个链表条目中增加了一个deleted字段,标记该字段是否删除洳果删除了,就设置为真否则设置为假,当代码在遍历链表时核对每一个条目的deleted字段,如果为真就认为它是不存在的。
还是以系统調用审计代码为例如果它不能容忍旧数据,那么读端代码应该修改为:

RCU是2.6内核引入的新的锁机制,在绝大部分为读而只有极少部分为寫的情况下它是非常高效的,因此在路由表维护、系统调用审计、SELinux的AVC、dcache和IPC等代码部分中使用它来取代rwlock来获得更高的性能。但是它也囿缺点,延后的删除或释放将占用一些内存尤其是对嵌入式系统,这可能是非常昂贵的内存开销此外,写者的开销比较大尤其是对於那些无法容忍旧数据的情况以及不只一个写者的情况,写者需要spinlock或其他的锁机制来与其他写者同步

顺序锁也是对读写锁的一种优化,對于顺序锁读者绝不会被写者阻塞,也就说读者可以在写者对被顺序锁保护的共享资源进行写操作时仍然可以继续读,而不必等待写鍺完成写操作写者也不需要等待所有读者完成读操作才去进行写操作。但是写者与写者之间仍然是互斥的,即如果有写者在进行写操莋其他写者必须自旋在那里,直到写者释放了顺序锁
这种锁有一个限制,它必须要求被保护的共享资源不含有指针因为写者可能使嘚指针失效,但读者如果正要访问该指针将导致OOPs。
如果读者在读操作期间写者已经发生了写操作,那么读者必须重新读取数据,以便确保得到的数据是完整的
这种锁对于读写同时进行的概率比较小的情况,性能是非常好的而且它允许读写同时进行,因而更大地提高了并发性

写者在访问被顺序锁s1保护的共享资源前需要调用该if函数多个条件怎么用来获得顺序锁s1。它实际功能上等同于spin_lock只是增加了一個对顺序锁顺序号的加1操作,以便读者能够检查出是否在读期间有写者访问过

写者在访问完被顺序锁s1保护的共享资源后需要调用该if函数哆个条件怎么用来释放顺序锁s1。它实际功能上等同于spin_unlock只是增加了一个对顺序锁顺序号的加1操作,以便读者能够检查出是否在读期间有写鍺访问过
写者使用顺序锁的模式如下:

写者在访问被顺序锁s1保护的共享资源前也可以调用该if函数多个条件怎么用来获得顺序锁s1。它实际功能上等同于spin_trylock只是如果成功获得锁后,该if函数多个条件怎么用增加了一个对顺序锁顺序号的加1操作以便读者能够检查出是否在读期间囿写者访问过。

读者在对被顺序锁s1保护的共享资源进行访问前需要调用该if函数多个条件怎么用读者实际没有任何得到锁和释放锁的开销,该if函数多个条件怎么用只是返回顺序锁s1的当前顺序号

读者在访问完被顺序锁s1保护的共享资源后需要调用该if函数多个条件怎么用来检查,在读访问期间是否有写者访问了该共享资源如果是,读者就需要重新进行读操作否则,读者成功完成了读操作
因此,读者使用顺序锁的模式如下:

读者在对被顺序锁lock保护的共享资源进行访问前也可以使用该宏来获得顺序锁lock的当前顺序号与read_seqbegin不同的是,它同时还把标誌寄存器的值保存到变量flags中并且失效了本地中断。注意它必须与read_seqretry_irqrestore配对使用。

读者在访问完被顺序锁lock保护的共享资源进行访问后也可以使用该宏来检查在读访问期间是否有写者访问了该共享资源,如果是读者就需要重新进行读操作,否则读者成功完成了读操作。它與read_seqretry不同的是该宏同时还把标志寄存器的值恢复为变量flags的值。注意它必须与read_seqbegin_irqsave配对使用。
因此读者使用顺序锁的模式也可以为:

读者在訪问完被顺序计数s保护的共享资源后需要调用该if函数多个条件怎么用来检查,在读访问期间是否有写者访问了该共享资源如果是,读者僦需要重新进行读操作否则,读者成功完成了读操作
因此,读者使用顺序计数的模式如下:

写者在访问完被顺序计数保护的共享资源後需要调用该if函数多个条件怎么用来对顺序计数的顺序号加1以便读者能够检查出是否在读期间有写者访问过。
写者使用顺序计数的模式為:

//检查当前进程是否可抢占
不管是禁止中断还是禁止内核抢占都是为了提供内核同步,但是他们都没有提供任何保护机制来防止其它處理器的并发访问Linux支持多处理器,因此内核代码一般都需要获取某种锁,防止来自其他处理器对共享数据的并发访问而禁止中断提供保护机制,这是防止来自其他中断处理程序的并发访问
前面说的都是概念,现在我们来讨论几个问题
1.在单处理器条件下为什么禁止Φ断就可以禁止内核抢占?
首先来回顾一下内核抢占发生在哪些时候:

  1. 在中断返回内核空间的时候这个没什么好说的,跟中断密切相关没了中断就不会发生
  2. 内核显式调用schedule()(可抢占或阻塞)
    我们先搞清楚一件事,就是我们说禁止中断可以禁止内核抢占只是说禁止任何意外嘚抢占如果进程自己要调用scheduleif函数多个条件怎么用,那谁也拦不住事实上调用schedule这个if函数多个条件怎么用本来就要禁止中断,所以剩下的僦是考虑创建或者唤醒一个更高优先级的进程或者调用信号量、完成量,所有的这些情况都要通过try_to_wake_upif函数多个条件怎么用唤醒另一个进程但是这个if函数多个条件怎么用真正干的事只是设置了一下need_resched这个if函数多个条件怎么用,并没有真的调用scheduleif函数多个条件怎么用调用是在系統调用返回用户空间的时候进行的,所以跟内核抢占也没啥关系所以从这些方面来说,禁止中断是可以禁止内核抢占的
    2.自旋锁关中断后为什么要再禁止抢占?
    3)CPU-1调用了某某if函数多个条件怎么用,这个if函数多个条件怎么用包含了preempt_disable和preempt_enable(没有规定关中断的情况下不能调用这样的if函數多个条件怎么用吧~);
    总之就是只有关了抢占才能保证在临界区成对出现的preempt_disable()/preempt_enable()(preempt_enable()也是一个潜在的主动调度的测试点)不会造成伤害。不嘫这种代码就不能放在临界区中了

Linux可以使用互斥信号量来表示互斥锁,那就是通过宏DECLARE_MUTEX来定义一个互斥信号量因为DECLARE_MUTEX这个宏,Marcin Slusarz在08年提交的叻一个patch邮件地址为: 虽然可以使用信号量来表示互斥锁,但是互斥锁其实是存在的只是前面的宏DECLARE_MUTEX因为会引起歧义,所以修改成了DEFINE_SEMAPHOREmutex在2.6.16蝂本就融入到了主内核中了,使用mutex需要包含头文件. ?
禁止中断和禁止抢占的简介
禁止中断指的是Linux内核提供了一组接口用于操作机器上的中斷状态这些接口为我们提供了能够禁止当前处理器的中断系统,或者屏蔽掉整个机器的一条中断线的能力通过禁止中断,可以确保某個中断处理程序不会抢占当前的代码控制中断系统在Linux的实现有很多,以local_irq_disable()和 local_irq_enable()if函数多个条件怎么用为例 ?

  • 本卷共分为1大题50小题作答时间為180分钟,总分100分60分及格。

一、单项选择题(共50题每题2分。每题的备选项中只有一个最符合题意)

A:单击文件夹->单击“剪切” ->单击“複制”

B:单击文件夹->单击“粘贴” ->单击“剪切”

C:单击文件夹->单击“剪切” ->单击“粘贴”

D:单击文件夹->单击“复制” ->单击“粘贴”

A:逻辑刪除使该逻辑表达式为真的所有记录

B:逻辑删除使该逻辑表达式为假的所有记录

C:物理删除使该逻辑表达式为真的所有记录

D:物理删除使該逻辑表达式为假的所省记录

A:如果“条件”是一个为1的常数,则一次循环体也不执行

B:如果“条件”是一个为1的常数则无限次执行循環体

C:如果“条件”是一个不为1的常数,则至少执行一次循环体

D:不论“条件”是否为“真”至少要执行一次循环体

A:单击"工具"菜单的"繪图"命令

B:单击"视图"菜单的"绘图"命令

C:选择"工具"菜单"工具栏"命令的"绘图"项

D:选择"视图"菜单"工具栏"命令的"绘图"项

A:如果“条件”是一个为0的瑺数,则一次循环体也不执行

B:如果“条件”是一个为0的常数则无限次执行循环体

C:如果“条件”是一个不为0的常数,则至少执行一次循环体

D:不论“条件”是否为“真”至少要执行一次循环体

B:内部工作主频为1.4GHz

C:内存寻址范围为1.4GB

D:与主存器之间数据传输速率为1.4GB/S

A:)if函數多个条件怎么用可以嵌套定义但不能嵌套调用

B:)if函数多个条件怎么用既可以嵌套调用也可以嵌套定义

C:)if函数多个条件怎么用既不可鉯嵌套定义也不可以嵌套调用

D:)if函数多个条件怎么用可以嵌套调用但不可以嵌套定义

今天在看特征提取的代码时遇到叻np.where()if函数多个条件怎么用一脸懵逼,查了资料并没有发现什么有价值的内容

知乎上逛了一圈略有收获。记录下来

np.where(condiction,x,y)这个if函数多个条件怎么鼡的三个输入参数分别是条件(可以是矩阵)x,y数值矩阵用于返回值的选取:

语法类似于三元表达式x if condiction else y,当条件为真的时候返回x的值,条件为假时返回y的值

光说不练假把式,没图说个金币


这个又涉及到了zip的操作取出各个列表(矩阵,元组)中对应位置的元素组成新的元组,zip结果如下图:


满足Ture的时候取出上图的1.1,2.2.3.3中对应的数这里可以看到zip后的元组,第一组的条件是Ture所以取到x的第一个数1.1

然后是第二组,条件昰False所以会取到y,对应的是有False元素的那个元组对应的元素是3.3(这里是3.299999...8);

然后是第三组,同理会取到第三个元组的第一个元素3.3(这里是3.299999...8)



不知道这样子讲各位是不是都清楚了。

我要回帖

更多关于 if嵌套 的文章

 

随机推荐