Home 内核-互斥与同步机制
Post
Cancel

内核-互斥与同步机制

竞争问题

在Linux系统中,程序的并发执行可能会导致共享资源竞争问题。共享资源是多个并发程序之间共同访问和使用的资源, 例如内存、文件、网络连接等,最常见的是应是内存变量了。当多个程序同时访问共享资源并试图进行修改时, 就可能导致竞争问题,导致不可预测的结果或执行错误。

常见的并发路径:

中断处理路径,中断上下文和进程上下文并发访问共享资源,这个在单核CPU上也能出现。

调度器抢占,对于支持抢占的调度器,在单核CPU上,也会导致进程与进程之间的并发。

多核并行,在多核处理器上,每个处理器之间是并行执行进程的,自然有并发。

常见的竞争问题如:

竞态条件(Race Condition):多个程序同时竞争访问和修改共享资源,由于执行顺序不确定,可能导致结果的不一致性。 例如,多个线程同时读取和写入同一个变量的值,可能导致数据错乱或丢失。本质上就是变量的写入不是原子的。一个线程在读写时, 还没完成,另一个线程又来读写相同的变量就会引起竞态条件。解决方式包括使用互斥锁(Mutex)、读写锁(ReadWrite Lock) 或原子操作来保护共享数据,确保一次只有一个程序可以修改数据。

死锁(Deadlock):多个程序或线程因为相互等待对方释放资源而无法继续执行的情况。当每个程序都持有某些资源并尝试获取 其他程序持有的资源时,可能会出现循环等待的情况,导致死锁。解决方式包括使用资源的有序分配、避免资源循环依赖、 以及使用死锁检测和恢复机制等。

活锁(LiveLock):活锁是指程序在尝试解决冲突时持续重试,但无法取得进展的状态。这可能是因为程序在冲突解决过程中过于主动, 导致不断重试而无法继续执行。解决活方式包括引入随机性、退避策略和合理的冲突解决算法等。

饥饿(Starvation):某些程序因为其他程序长时间占用共享资源而无法得到满足的情况,通常是高优先级线程一直占用某资源导致 低优先级线程无法获取而处于饥饿状态。解决方式包括使用公平调度策略,合理的优先级设置,时间片轮转调度,使用锁的超时机制等。

性能下降:并发程序中,如果对共享资源的访问没有良好的调度和管理,可能导致性能下降。例如,过多的锁竞争可能导致程序频繁地等待锁, 从而浪费了大量的时间。解决方式包括使用细粒度锁、减少锁竞争、使用无锁数据结构、以及合理的任务划分和调度策略等。

一些同步机制

竞争可能导致的问题有很多,解决方式也繁杂。这里仅列举一些linux系统中的同步机制等,主要能解决竞态条件和及衍生的问题。

互斥锁(Mutex):用于保护临界区代码片段,确保一次只有一个线程可以进入。通过加锁和解锁操作来保证临界区的互斥访问。 程序在访问共享资源之前,必须先获取互斥锁,操作完成后再释放锁,以确保共享资源的独占访问。

读写锁(Read/Write Lock):在读操作和写操作之间提供更细粒度的并发控制。同一时刻,允许多个线程同时读取共享资源,但只有一个线程可以进行写操作。可以提高读操作的并发性能。

条件变量(Condition Variable):用于线程间的同步和通信,允许线程等待某个条件发生或者被其他线程通知。

原子操作(Atomic Operations):提供了原子性的读取和写入操作,可以在没有锁的情况下进行对共享数据的操作,有效避免竞争条件。

信号量(Semaphore):信号量是一种计数器,用于控制对共享资源的访问数量,可以设置为允许一定数量的线程同时访问。程序在访问资源之前必须先获取信号量,访问完成后再释放信号量。

percpu(per CPU):一种变量类型,它允许每个CPU核心独立地访问自己的数据副本,提高了并发性和性能,并减少了竞争条件的发生。在多核系统中,每个CPU核心都有自己的寄存器集合和缓存, percpu变量允许将数据在不同的CPU核心上独立地存储和访问,以提高并发性和性能。用于处理多核系统中的并发访问和共享数据问题。

以上是一些常见的解决共享资源竞争问题的方式,Linux系统还提供了其他的同步和并发控制机制,如条件锁、屏障等,可以根据具体情况选择合适的方法来解决并发执行导致的共享资源竞争问题。

临界区:特指对共享资源访问的代码片段,也就是可能引起竞争问题的代码

This post is licensed under CC BY 4.0 by the author.

Linux设备模型

关于local_irq_save(了解)