对于特定场景,什么是最好的linux内核锁定机制 [英] What's the best linux kernel locking mechanism for a specific scenario

查看:292
本文介绍了对于特定场景,什么是最好的linux内核锁定机制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要为此方案解决锁定问题:


  1. 多CPU系统。

  2. 所有的CPU都使用通用(软件)资源。

  3. 只读访问资源非常常见。 (传入网络数据包的处理)

  4. 写访问频率低得多。

目前我使用 read_lock_bh write_lock_bh (spinlocks)机制。
问题是CPU的数量越多,我在编写器上下文中得到的软锁定就越多。



我阅读了这本书
但是不能完全理解读者或写者在使用自旋锁时是否获得优先权。



所以问题是:


  1. Linux自旋锁机制是否优先阅读器/记者/他们都不是吗?

  2. 有没有更好的机制,我可以使用,以避免这些软锁定在我的情况,或者也许一种方式,


  3. 感谢您,
    Nir ​​

    解决方案

    以下是来自 Essential Linux设备的直接引用驱动程序,这可能是您要找的。



    读写器锁定



    另一种专门的并发调节机制是自旋锁的读写器变体。如果
    临界区的使用使得单独的线程读取或写入共享数据结构,但不做
    ,那么这些锁是自然适合的。在临界区内允许多个读取器线程同时。
    读者螺旋锁定义如下:

      rwlock_t myrwlock = RW_LOCK_UNLOCKED; 

    read_lock(& myrwlock); / *获取读锁器* /
    / * ...关键区域... * /
    read_unlock(& myrwlock); / *释放锁* /

    但是,如果写线程进入临界区,其他读写器线程不允许在里面。要使用
    writer spinlocks,你可以这样写:

      rwlock_t myrwlock = RW_LOCK_UNLOCKED; 

    write_lock(&myrwlock); / *获取写锁定* /
    / * ...关键区域... * /
    write_unlock(& myrwlock); / *释放锁* /

    查看 net中存在的IPX路由代码/ipx/ipx_route.c 用于读写器螺旋锁的实际示例。 A
    读写器锁调用 ipx_routes_lock 保护IPX路由表不受同时访问。线程
    需要查找路由表来转发数据包请求读取器锁。需要添加的线程或
    从路由表中删除条目会获取写入程序锁。这提高了性能,因为通常
    比路由表更新的路由表查找更多的实例。



    与普通的自旋锁一样,读写器锁也有相应的irq变量 - 即 read_lock_irqsave()
    read_lock_irqrestore() write_lock_irqsave ) write_lock_irqrestore()。这些
    函数的语义与常规自旋锁的语义相似。



    2.6内核中引入的顺序锁或seqlocks是读写器锁,是超过
    的读者。如果对变量远程超过读访问的写操作,这是有用的。例如本章前面讨论的
    jiffies_64 变量。写者线程不等待可能在
    内的读者是关键部分。因此,读者线程可能发现他们在关键部分内的条目失败了
    ,可能需要重试:

      u64 get_jiffies_64(void)/ *定义在kernel / time.c * / 
    {
    unsigned long seq;
    u64 ret;
    do {
    seq = read_seqbegin(& xtime_lock);
    ret = jiffies_64;
    } while(read_seqretry(& xtime_lock,seq));
    return ret;
    }

    写保护程序使用 write_seqlock code>和 write_sequnlock()



    2.6内核引入了另一种机制,复制更新(RCU), 当读者远远超过作者 时,这会提高
    的性能。基本思想是读取器线程可以在没有
    锁定的情况下执行。写程序线程更复杂。它们对数据结构的副本执行更新操作,
    替换读取器看到的指针。保持原始副本,直到所有CPU上的下一个上下文切换为
    ,确保完成所有正在进行的读取操作。请注意,使用RCU比使用迄今为止讨论的
    原语更有用,只有在您确定它是正确的工作工具时,才应使用RCU。 RCU数据
    结构和接口函数在 include / linux / rcupdate.h 中定义。在
    文档/ RCU / * 中有大量文档。



    示例,请查看 fs / dcache.c 。在Linux上,每个文件与目录条目
    信息(存储在名为dentry的结构中),元数据信息(存储在inode中)和实际数据
    (存储在数据块中)相关联。每次对文件进行操作时,将解析文件路径中的组件,并获取
    相应的dentries。 dentry被保存在一个称为dcache的数据结构中,以
    加速未来的操作。在任何时候,dcache查找的次数比dcache更新的次数多得多,因此对dcache的
    引用使用RCU原语保护。


    I need to solve a locking problem for this scenario:

    1. A multi CPU system.
    2. All of the CPU's use a common (software) resource.
    3. Read only access to the resource is very common. (Processing of incoming network packets)
    4. Write access is a lot less frequent. (Pretty much configuration changes only).

    Currently I use the read_lock_bh, write_lock_bh (spinlocks) mechanism. The problem is that the more CPU's, the more I get soft lockups in a writer context.

    I read the concurrency chapter in this book, But couldn't quite understand whether the reader or the writer will get priority when using spin locks.

    So the questions are:

    1. Does the Linux spinlock mechanism give priority the reader/writer/none of them?
    2. Is there a better mechanism I can use in order to avoid those soft lockups in my scenario, or maybe a way for me to give priority to the writer whenever it tries to obtain the lock, while using my current solution?

    Thanks, Nir

    解决方案

    Here's a direct quote from Essential Linux Device Drivers which might be what you're looking for. It seems the part dealing with RCU at the end may be what you're interested in.

    Reader-Writer Locks

    Another specialized concurrency regulation mechanism is a reader-writer variant of spinlocks. If the usage of a critical section is such that separate threads either read from or write to a shared data structure, but don't do both, these locks are a natural fit. Multiple reader threads are allowed inside a critical region simultaneously. Reader spinlocks are defined as follows:

    rwlock_t myrwlock = RW_LOCK_UNLOCKED;
    
    read_lock(&myrwlock);             /* Acquire reader lock */
    /* ... Critical Region ... */
    read_unlock(&myrwlock);           /* Release lock */
    

    However, if a writer thread enters a critical section, other reader or writer threads are not allowed inside. To use writer spinlocks, you would write this:

    rwlock_t myrwlock = RW_LOCK_UNLOCKED;
    
    write_lock(&myrwlock);            /* Acquire writer lock */
    /* ... Critical Region ... */
    write_unlock(&myrwlock); /* Release lock */
    

    Look at the IPX routing code present in net/ipx/ipx_route.c for a real-life example of a reader-writer spinlock. A reader-writer lock called ipx_routes_lock protects the IPX routing table from simultaneous access. Threads that need to look up the routing table to forward packets request reader locks. Threads that need to add or delete entries from the routing table acquire writer locks. This improves performance because there are usually far more instances of routing table lookups than routing table updates.

    Like regular spinlocks, reader-writer locks also have corresponding irq variants—namely, read_lock_irqsave(), read_lock_irqrestore(), write_lock_irqsave(), and write_lock_irqrestore(). The semantics of these functions are similar to those of regular spinlocks.

    Sequence locks or seqlocks, introduced in the 2.6 kernel, are reader-writer locks where writers are favored over readers. This is useful if write operations on a variable far outnumber read accesses. An example is the jiffies_64 variable discussed earlier in this chapter. Writer threads do not wait for readers who may be inside a critical section. Because of this, reader threads may discover that their entry inside a critical section has failed and may need to retry:

    u64 get_jiffies_64(void) /* Defined in kernel/time.c */
    {
       unsigned long seq;
       u64 ret;
       do {
          seq = read_seqbegin(&xtime_lock);
          ret = jiffies_64;
       } while (read_seqretry(&xtime_lock, seq));
       return ret;
    }
    

    Writers protect critical regions using write_seqlock() and write_sequnlock().

    The 2.6 kernel introduced another mechanism called Read-Copy Update (RCU), which yields improved performance when readers far outnumber writers. The basic idea is that reader threads can execute without locking. Writer threads are more complex. They perform update operations on a copy of the data structure and replace the pointer that readers see. The original copy is maintained until the next context switch on all CPUs to ensure completion of all ongoing read operations. Be aware that using RCU is more involved than using the primitives discussed thus far and should be used only if you are sure that it's the right tool for the job. RCU data structures and interface functions are defined in include/linux/rcupdate.h. There is ample documentation in Documentation/RCU/*.

    For an RCU usage example, look at fs/dcache.c. On Linux, each file is associated with directory entry information (stored in a structure called dentry), metadata information (stored in an inode), and actual data (stored in data blocks). Each time you operate on a file, the components in the file path are parsed, and the corresponding dentries are obtained. The dentries are kept cached in a data structure called the dcache, to speed up future operations. At any time, the number of dcache lookups is much more than dcache updates, so references to the dcache are protected using RCU primitives.

    这篇关于对于特定场景,什么是最好的linux内核锁定机制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆