Linux_C_同步_内核原子_自旋锁_互斥锁
- 格式:doc
- 大小:55.00 KB
- 文档页数:6
linux进程间同步机制一、进程间同步的概念在多进程系统中,进程间的通信是必要的,但同时也要防止进程间的相互干扰和数据污染。
进程间的同步机制就是用于解决这一问题的机制,它通过控制进程间的执行顺序、共享资源访问等方式,确保进程间的正确协作。
1. 互斥锁(Mutex)互斥锁是一种常用的进程同步机制,用于保护共享资源,防止多个进程同时访问和修改共享资源,导致数据错误或不一致。
使用互斥锁时,进程需要先获取锁才能访问共享资源,释放锁后才能进行其他操作。
示例代码:```cpthread_mutex_t mutex;pthread_mutex_lock(&mutex);// 访问共享资源pthread_mutex_unlock(&mutex);```2. 信号量(Semaphore)信号量是一种计数器,用于控制对共享资源的访问。
它可以实现进程间的同步和互斥,确保在任何时刻只有一个进程可以访问共享资源。
示例代码:```c#define MAX_COUNT 5sem_t sem;sem_wait(&sem); // 等待信号量释放// 访问共享资源sem_post(&sem); // 释放信号量```3. 屏障(Barrier)屏障是一种用于同步进程的机制,用于确保所有进程在执行完一定操作后才能继续执行。
在多线程或多进程编程中,屏障可以用于确保所有线程或进程完成了某个阶段的准备工作后,再继续执行后续的操作。
示例代码:```cpthread_barrier_t barrier;pthread_barrier_wait(&barrier); // 等待所有线程或进程到达屏障位置```4. 管道(Pipe)和消息队列(Message Queue)管道和消息队列是用于进程间通信的机制,它们允许一个进程向另一个进程发送消息或数据。
通过管道和消息队列,进程间可以异步地交换数据,从而实现同步。
linux原子操作函数Linux原子操作函数是一组用于实现多线程同步和互斥的函数。
在并发编程中,多个线程同时访问共享资源时,可能会导致数据的不一致或竞争条件的发生。
原子操作函数可以保证多线程之间的顺序性和一致性,从而避免了竞争条件的产生。
原子操作函数的特点是不可分割和不可中断,即在执行原子操作期间,不会被其他线程打断或者分割成多个步骤执行。
这种特性保证了原子操作的完整性,使多线程之间可以安全地共享资源。
Linux提供了多个原子操作函数,其中最常用的有以下几个:1. atomic_inc(原子增加):该函数用于对指定的整型变量进行原子递增操作。
它保证了递增操作的完整性,不会被其他线程打断或者分割成多个步骤执行。
该函数常用于实现计数器等功能。
2. atomic_dec(原子减少):与atomic_inc函数类似,该函数用于对指定的整型变量进行原子递减操作。
同样地,它也保证了递减操作的完整性。
3. atomic_add(原子加法):该函数用于对指定的整型变量进行原子加法操作。
它可以将一个给定的值原子地加到指定的变量上,保证了整个加法操作的完整性和一致性。
4. atomic_sub(原子减法):与atomic_add函数类似,该函数用于对指定的整型变量进行原子减法操作。
它可以将一个给定的值原子地从指定的变量上减去。
5. atomic_xchg(原子交换):该函数用于原子地交换两个指定的值。
它可以保证交换操作的完整性,不会被其他线程打断。
6. atomic_cmpxchg(原子比较并交换):该函数用于比较指定的变量的值与给定的期望值是否相等,如果相等则用新的值替换旧的值。
它是一种常用的原子操作,可以用于实现互斥锁等功能。
除了上述常用的原子操作函数外,Linux还提供了其他一些原子操作函数,如atomic_and、atomic_or、atomic_xor等,它们分别用于进行按位与、按位或和按位异或的原子操作。
linux cpu核访问同一片内存的保护机制在多核处理器系统中,多个 CPU 核心可以同时访问同一片内存。
为了确保在并发访问中数据的一致性,Linux 使用了一些机制来保护共享内存区域,防止并发访问导致数据不一致或错误。
以下是 Linux 中 CPU 核访问同一片内存的保护机制:1. 原子操作:• Linux 提供了一系列原子操作,确保在一个原子操作中对共享内存的访问是不可中断的。
例如,atomic_t 类型和相关的原子操作函数可以确保某些操作是原子的,不会被中断。
2. 自旋锁(Spin Lock):•自旋锁是一种在多核系统中实现互斥的手段。
当一个核心获得了自旋锁,其他核心如果需要访问被保护的共享内存,就需要等待。
它们会不断尝试获取锁,而不是进入睡眠状态,因此称为“自旋”。
3. 信号量:•信号量是一种更高级的同步机制,可以用于实现对共享资源的访问控制。
Linux 提供了 semaphore 相关的 API,允许程序员使用信号量来保护共享内存。
4. 读写锁(Read-Write Lock):•读写锁允许多个核心同时读取共享内存,但在写入时必须互斥。
这种机制在对于读访问比写访问频繁的场景中可以提高性能。
5. 屏障(Memory Barriers):•内存屏障用于强制 CPU 在执行指令时遵循一定的内存访问顺序。
这对于确保在多核系统中,不同核心看到的内存访问顺序是一致的,从而保证数据的一致性。
6. 写时复制(Copy-On-Write):•对于一些共享的数据结构,Linux 可以使用写时复制技术。
当一个核心需要修改数据时,它会复制一份私有副本,而不是直接修改共享数据。
这样可以避免多核心同时写入导致的冲突。
这些机制的选择取决于应用的需求和性能特性。
在编写多线程或多进程应用程序时,程序员需要根据实际情况选择合适的同步机制来确保数据的一致性和正确性。
互斥锁和自旋锁的区别
自旋锁是一种互斥锁的实现方式而已,相比一般的互斥锁会在等待期间放弃cpu,自
旋锁(spinlock)则是不断循环并测试锁的状态,这样就一直占着cpu。
互斥锁:用于保护临界区,确保同一时间只有一个线程访问数据。
对共享资源的访问,先对互斥量进行加锁,如果互斥量已经上锁,调用线程会阻塞,直到互斥量被解锁。
在完
成了对共享资源的访问后,要对互斥量进行解锁。
临界区:每个进程中出访临界资源的那段程序称作临界区,每次只容许一个进程步入
临界区,步入后不容许其他进程步入。
自旋锁:与互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙
等(自旋)阻塞状态。
用在以下情况:锁持有的时间短,而且线程并不希望在重新调度上
花太多的成本。
“原地打转”。
磁矩门锁与不相容门锁的区别:线程在提出申请磁矩门锁的时候,线程不能被挂上,
而是处在忙等的状态。
信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
它常作为
一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
因此,主要作为
进程间以及同一进程内不同线程之间的同步手段。
kernel中的互斥锁1. 什么是互斥锁?在计算机科学中,互斥锁(Mutex)是一种用于控制对共享资源的访问的同步机制。
它允许多个线程或进程同时访问共享资源,但只允许一个线程或进程在任意时刻访问该资源。
互斥锁的主要目的是防止多个线程或进程同时访问共享资源,从而避免竞争条件(Race Condition)的发生。
竞争条件是指多个线程或进程在没有足够同步机制的情况下对共享资源进行读写操作,导致结果的不确定性。
2. 互斥锁在kernel中的应用在kernel中,互斥锁被广泛应用于保护共享数据结构的访问。
由于kernel是一个多线程的环境,不同的线程可能同时访问同一个数据结构,而互斥锁可以确保在任意时刻只有一个线程可以访问该数据结构,从而避免数据的不一致性和竞争条件的发生。
互斥锁在kernel中的应用非常广泛,例如:•保护内核数据结构的访问:kernel中有许多重要的数据结构,如进程控制块(PCB)、文件描述符表等,这些数据结构需要被多个线程或进程同时访问。
使用互斥锁可以确保对这些数据结构的访问是安全的。
•同步设备访问:在kernel中,许多设备是共享的,多个线程或进程可能同时访问同一个设备。
使用互斥锁可以确保对设备的访问是顺序的,避免冲突和不一致性。
•保护临界区:在kernel中,有些代码段是临界区,即多个线程或进程不能同时执行的代码段。
使用互斥锁可以确保在任意时刻只有一个线程或进程可以执行临界区的代码,从而避免竞争条件的发生。
3. kernel中的互斥锁实现在Linux kernel中,互斥锁是由mutex结构体表示的。
该结构体定义在<linux/mutex.h>头文件中,包含了互斥锁的各种属性和方法。
互斥锁的基本使用方法如下:#include <linux/mutex.h>struct mutex my_mutex;// 初始化互斥锁mutex_init(&my_mutex);// 获取互斥锁mutex_lock(&my_mutex);// 访问共享资源// 释放互斥锁mutex_unlock(&my_mutex);互斥锁的初始化使用mutex_init函数,该函数会将互斥锁的各种属性初始化为默认值。
C++中有几种常见的线程同步机制,包括原子锁、自旋锁和互斥锁。
**原子锁(Atomic Lock)**是一种基于原子操作的锁,用于实现对共享资源的原子访问。
原子锁通常使用原子操作来确保在多个线程中对共享资源的原子性访问。
C++11引入了std::atomic<>模板类来支持原子操作,其中包含了各种原子类型,如
std::atomic_flag和std::atomic<T>,可以用于实现原子锁。
**自旋锁(Spinlock)**是一种忙等待锁,当一个线程尝试获取锁时,如果锁已经被其他线程占用,该线程会一直循环等待,直到锁可用。
自旋锁适用于短时间内锁被占用的情况,避免了线程切换的开销。
C++中没有内置的自旋锁,但可以使用标准库提供的std::atomic_flag来实现简单的自旋锁。
**互斥锁(Mutex)**是最常见的线程同步机制,用于保护共享资源不被并发访问。
当一个线程获得互斥锁后,其他线程必须等待该线程释放锁才能继续执行。
C++中提供了std::mutex类用于实现互斥锁,可以使用std::unique_lock或std::lock_guard来保证在作用域结束时自动释放互斥锁。
这些线程同步机制各有优缺点,选择合适的机制取决于具体的应用场景和性能需求。
linux中的同步机制Linux中的同步机制在Linux操作系统中,同步机制是一种重要的机制,用于控制并发访问共享资源的顺序和互斥。
它确保多个进程或线程能够有序地访问共享资源,避免数据竞争和不一致的结果。
本文将介绍Linux中常用的同步机制,包括互斥锁、条件变量、信号量和屏障等。
一、互斥锁(Mutex)互斥锁是一种最常见的同步机制,用于保护共享资源的访问。
在互斥锁的帮助下,只有一个进程或线程能够获得锁,其他进程或线程需要等待锁的释放。
Linux提供了多种互斥锁的实现,如pthread_mutex_t和std::mutex等。
使用互斥锁需要注意避免死锁和竞态条件等问题。
二、条件变量(Condition Variable)条件变量是一种用于线程间通信的同步机制,它允许线程在满足特定条件之前等待,从而避免了忙等待的问题。
在Linux中,条件变量通常与互斥锁一起使用。
当某个线程发现条件不满足时,它可以调用条件变量的等待函数将自己阻塞,直到其他线程满足条件并发出信号,唤醒等待的线程。
三、信号量(Semaphore)信号量是一种用于控制并发访问的同步机制,它可以实现对资源的计数和管理。
Linux提供了两种类型的信号量:二进制信号量和计数信号量。
二进制信号量只有两种状态(0和1),用于互斥访问共享资源;计数信号量可以有多个状态,用于限制并发访问的数量。
通过使用信号量,可以实现进程或线程之间的同步和互斥。
四、屏障(Barrier)屏障是一种用于线程同步的机制,它在多个线程到达指定点之前将它们阻塞,直到所有线程都到达后才继续执行。
屏障可以用于并行计算中的阶段同步,确保每个阶段的计算完成后再进行下一阶段的计算。
在Linux中,可以使用pthread_barrier_t来创建和操作屏障。
五、读写锁(ReadWrite Lock)读写锁是一种特殊的锁机制,用于在读操作和写操作之间提供更好的并发性。
读写锁允许多个线程同时读取共享资源,但只允许一个线程进行写操作。
c语言锁的类型和概念C语言中的锁是一种同步机制,用于控制多个线程或进程对共享资源的访问。
锁可以确保在任何时候只有一个线程或进程可以访问共享资源,以避免数据竞争和其他并发问题。
C语言中有几种不同类型的锁,每种锁都有其自己的特点和用途。
下面将介绍这些不同类型的锁及其概念。
1. 互斥锁互斥锁是最常见的一种锁类型,也是最简单和最基本的一种。
互斥锁可以确保在任何时候只有一个线程可以访问共享资源。
当一个线程获得了互斥锁时,其他线程必须等待该线程释放该锁后才能访问共享资源。
在C语言中,使用pthread_mutex_t结构体来表示互斥锁。
通过pthread_mutex_init函数初始化互斥锁,并使用pthread_mutex_lock和pthread_mutex_unlock函数来获取和释放该锁。
2. 读写锁读写锁是另一种常见的锁类型,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。
这对于读取频繁但写入较少的应用程序非常有用。
在C语言中,使用pthread_rwlock_t结构体来表示读写锁。
通过pthread_rwlock_init函数初始化读写锁,并使用pthread_rwlock_rdlock和pthread_rwlock_wrlock函数来获得读取和写入锁,使用pthread_rwlock_unlock函数来释放锁。
3. 条件变量条件变量是一种允许线程等待特定条件的同步机制。
当一个线程需要等待某个条件满足时,它可以通过条件变量进入休眠状态,直到另一个线程发出信号通知该条件已经满足。
在C语言中,使用pthread_cond_t结构体来表示条件变量。
通过pthread_cond_init函数初始化条件变量,并使用pthread_cond_wait和pthread_cond_signal函数来等待和发出信号。
4. 自旋锁自旋锁是一种基于忙等待的锁类型,它允许线程在没有被阻塞的情况下等待共享资源。
linux线程间同步和互斥的方法随着计算机技术的飞速发展,多线程应用已经变得越来越普遍。
在Linux操作系统中,多线程是一种强大的工具,它允许程序同时执行多个任务,从而提高系统的并发性和效率。
然而,多线程应用也带来了一些挑战,如线程间的同步和互斥问题。
本文将介绍Linux线程间同步和互斥的方法。
一、互斥(Mutex)互斥是最基本的同步机制之一,用于保护共享资源,防止多个线程同时访问同一资源而造成数据混乱。
在Linux中,可以使用pthread_mutex_t类型来创建互斥锁。
使用pthread_mutex_lock()函数来锁定互斥锁,确保同一时刻只有一个线程可以访问被保护的资源;使用pthread_mutex_unlock()函数来解锁互斥锁,允许其他线程访问该资源。
二、条件变量(ConditionVariable)条件变量是一种更复杂的同步机制,它允许一个或多个线程在满足某个条件时被唤醒。
在Linux中,可以使用pthread_cond_t类型来创建条件变量。
线程可以通过pthread_cond_wait()函数进入等待状态,直到条件满足时被唤醒。
使用pthread_cond_signal()或pthread_cond_broadcast()函数来通知其他等待的线程。
三、读写锁(Read-WriteLock)读写锁是一种更高效的同步机制,它允许多个读线程同时访问共享资源,但在写操作时只允许一个写线程访问。
在Linux中,可以使用pthread_rwlock_t类型来创建读写锁。
读线程可以同时获取读锁,而写线程必须获取写锁。
当写线程释放写锁时,读线程可以再次获取读锁。
这种机制可以提高并发性能,降低资源争用的开销。
四、信号量(Semaphore)信号量是一种用于控制并发访问的计数器。
它通常用于计数有限的资源数量,如文件描述符或磁盘空间。
在Linux中,可以使用sem_t 类型来创建信号量。
使用sem_wait()函数来减少信号量的值,表示消耗了一个资源;使用sem_post()函数来增加信号量的值,表示释放了一个资源。
Linux中的互斥锁、信号量和自旋锁都是常用的同步机制,用于协调多个线程或进程对共享资源的访问。
1. 互斥锁(Mutex):也称为互斥量,是最基本的锁机制。
它提供了互斥访问共享资源的能力,当一个线程获得互斥锁后,其他线程将被阻塞,直到该线程释放锁为止。
在Linux内核中,mutex 的实现原理基于底层硬件的支持,通过使用汇编指令实现锁的获取和释放。
2. 信号量(Semaphore):信号量是一种计数器,用于控制对共享资源的访问次数。
在Linux内核中,信号量的实现原理基于系统调用和内核函数,通过维护一个计数器来记录可用资源数量。
当一个线程需要访问共享资源时,会尝试获取信号量,如果计数器为正数,则该线程可以访问共享资源,否则该线程将被阻塞。
3. 自旋锁(Spinlock):自旋锁是一种基于忙等待的同步机制。
当一个线程尝试获取自旋锁时,如果锁已经被其他线程持有,则该线程将自旋(忙等待)直到锁被释放。
自旋锁适用于保护临界区代码较短且短暂占用共享资源的情况。
在Linux内核中,自旋锁的实现原理基于底层硬件的支持,通过使用汇编指令实现锁的获取和释放。
需要注意的是,以上三种锁机制都是通过系统调用或特定的库函数在用户空间或内核空间实现的。
在使用锁的过程中,需要注意
避免死锁(Deadlock)和饥饿(Starvation)等并发编程中常见的问题。
Linux 同步方法剖析内核原子,自旋锁和互斥锁你也许接触过并发(concurrency)、临界段(critical section)和锁定,不过怎么在内核中使用这些概念呢?本文讨论了 2.6 版内核中可用的锁定机制,包括原子运算符(atomic operator)、自旋锁(spinlock)、读/写锁(reader/writer lock)和内核信号量(kernel semaphore)。
本文还探讨了每种机制最适合应用到哪些地方,以构建安全高效的内核代码。
本文讨论了 Linux 内核中可用的大量同步或锁定机制。
这些机制为 2.6.23 版内核的许多可用方法提供了应用程式接口(API)。
不过在深入学习 API 之前,首先需要明白将要解决的问题。
并发和锁定当存在并发特性时,必须使用同步方法。
当在同一时间段出现两个或更多进程并且这些进程彼此交互(例如,共享相同的资源)时,就存在并发现象。
在单处理器(uniprocessor,UP)主机上可能发生并发,在这种主机中多个线程共享同一个 CPU 并且抢占(preemption)创建竞态条件。
抢占通过临时中断一个线程以执行另一个线程的方式来实现 CPU 共享。
竞态条件发生在两个或更多线程操纵一个共享数据项时,其结果取决于执行的时间。
在多处理器(MP)计算机中也存在并发,其中每个处理器中共享相同数据的线程同时执行。
注意在 MP 情况下存在真正的并行(parallelism),因为线程是同时执行的。
而在 UP 情形中,并行是通过抢占创建的。
两种模式中实现并发都较为困难。
Linux 内核在两种模式中都支持并发。
内核本身是动态的,而且有许多创建竞态条件的方法。
Linux 内核也支持多处理(multiprocessing),称为对称多处理(SMP)。
临界段概念是为解决竞态条件问题而产生的。
一个临界段是一段不允许多路访问的受保护的代码。
这段代码能操纵共享数据或共享服务(例如硬件外围设备)。
临界段操作时坚持互斥锁(mutual exclusion)原则(当一个线程处于临界段中时,其他所有线程都不能进入临界段)。
临界段中需要解决的一个问题是死锁条件。
考虑两个独立的临界段,各自保护不同的资源。
每个资源拥有一个锁,在本例中称为 A 和 B。
假设有两个线程需要访问这些资源,线程 X 获取了锁 A,线程 Y 获取了锁 B。
当这些锁都被持有时,每个线程都试图占有其他线程当前持有的锁(线程 X 想要锁 B,线程 Y 想要锁 A)。
这时候线程就被死锁了,因为他们都持有一个锁而且还想要其他锁。
一个简单的解决方案就是总是按相同次序获取锁,从而使其中一个线程得以完成。
还需要其他解决方案检测这种情形。
表 1 定义了此处用到的一些重要的并发术语。
表 1. 并发中的重要定义Linux 同步方法如果你了解了一些基本理论并且明白了需要解决的问题,接下来将学习 Linux 支持并发和互斥锁的各种方法。
在以前,互斥锁是通过禁用中断来提供的,不过这种形式的锁定效率比较低(目前在内核中仍然存在这种用法)。
这种方法也不能进行扩展,而且不能确保其他处理器上的互斥锁。
在以下关于锁定机制的讨论中,我们首先看一下原子运算符,他能保护简单变量(计数器和位掩码(bitmask))。
然后介绍简单的自旋锁和读/写锁,他们构成了一个 SMP 架构的忙等待锁(busy-wait lock)覆盖。
最后,我们讨论构建在原子 API 上的内核互斥锁。
原子操作Linux 中最简单的同步方法就是原子操作。
原子意味着临界段被包含在 API 函数中。
不必额外的锁定,因为 API 函数已包含了锁定。
由于 C 不能实现原子操作,因此 Linux 依靠底层架构来提供这项功能。
各种底层架构存在非常大差异,因此原子函数的实现方法也各不相同。
一些方法完全通过汇编语言来实现,而另一些方法依靠 c 语言并且使用 local_irq_save 和 local_irq_restore 禁用中断。
旧的锁定方法在内核中实现锁定的一种不太好的方法是通过禁用本地 CPU 的硬中断。
这些函数均可用并且仍得到使用(有时用于原子运算符),但我们并不推荐使用。
local_irq_save 例程禁用中断,而 local_irq_restore 恢复以前启用过的中断。
这些例程都是可重入的(reentrant),也就是说他们能在其他例程上下文中被调用。
当需要保护的数据非常简单时,例如一个计数器,原子运算符是种最佳的方法。
尽管原理简单,原子 API 提供了许多针对不同情形的运算符。
下面是个使用此 API 的示例。
要声明一个原子变量(atomic variable),首先声明一个 atomic_t 类型的变量。
这个结构包含了单个 int 元素。
接下来,需确保你的原子变量使用 ATOMIC_INIT 符号常量进行了初始化。
在清单 1 的情形中,原子计数器被设置为 0。
也能使用 atomic_set function 在运行时对原子变量进行初始化。
清单 1. 创建和初始化原子变量atomic_t my_counter ATOMIC_INIT(0);... or ...atomic_set( &my_counter, 0 );原子 API 支持一个涵盖许多用例的富函数集。
能使用 atomic_read 读取原子变量中的内容,也能使用atomic_add 为一个变量添加指定值。
最常用的操作是使用 atomic_inc 使变量递增。
也可用减号运算符,他的作用和相加和递增操作相反。
清单 2. 演示了这些函数。
清单 2. 简单的算术原子函数val = atomic_read( &my_counter );atomic_add( 1, &my_counter );atomic_inc( &my_counter );atomic_sub( 1, &my_counter );atomic_dec( &my_counter );该 API 也支持许多其他常用用例,包括 operate-and-test 例程。
这些例程允许对原子变量进行操纵和测试(作为一个原子操作来执行)。
一个叫做 atomic_add_negative 的特别函数被添加到原子变量中,然后当结果值为负数时返回真(true)。
这被内核中一些依赖于架构的信号量函数使用。
许多函数都不返回变量的值,但两个函数除外。
他们会返回结果值(atomic_add_return 和atomic_sub_return),如清单 3所示。
清单 3. Operate-and-test 原子函数if (atomic_sub_and_test( 1, &my_counter )) {// my_counter is zero}if (atomic_dec_and_test( &my_counter )) {// my_counter is zero}if (atomic_inc_and_test( &my_counter )) {// my_counter is zero}if (atomic_add_negative( 1, &my_counter )) {// my_counter is less than zero}val = atomic_add_return( 1, &my_counter ));val = atomic_sub_return( 1, &my_counter ));如果你的架构支持 64 位长类型(BITS_PER_LONG 是 64 的),那么能使用 long_t atomic 操作。
能在linux/include/asm-generic/atomic.h 中查看可用的长操作(long operation)。
原子 API 还支持位掩码(bitmask)操作。
跟前面提到的算术操作不相同,他只包含设置和清除操作。
许多驱动程式使用这些原子操作,特别是 SCSI。
位掩码原子操作的使用跟算术操作存在细微的差别,因为其中只有两个可用的操作(设置掩码和清除掩码)。
使用这些操作前,需要提供一个值和将要进行操作的位掩码,如清单 4 所示。
清单 4. 位掩码原子函数unsigned long my_bitmask;atomic_clear_mask( 0, &my_bitmask );atomic_set_mask( 1, &my_bitmask );原子 API 原型原子操作依赖于架构,能在 ./linux/include/asm-/atomic.h 中找到。
自旋锁自旋锁是使用忙等待锁来确保互斥锁的一种特别方法。
如果锁可用,则获取锁,执行互斥锁动作,然后释放锁。
如果锁不可用,线程将忙等待该锁,直到其可用为止。
忙等待看起来效率低下,但他实际上比将线程休眠然后当锁可用时将其唤醒要快得多。
自旋锁只在 SMP 系统中才有用,不过因为你的代码最终将会在 SMP 系统上运行,将他们添加到 UP 系统是个明智的做法。
自旋锁有两种可用的形式:完全锁(full lock)和读写锁。
首先看一下完全锁。
首先通过一个简单的声明创建一个新的自旋锁。
这能通过调用 spin_lock_init 进行初始化。
清单 5 中显示的每个变量都会实现相同的结果。
清单 5. 创建和初始化自旋锁spinlock_t my_spinlock = SPIN_LOCK_UNLOCKED;... or ...DEFINE_SPINLOCK( my_spinlock );... or ...spin_lock_init( &my_spinlock );定义了自旋锁之后,就能使用大量的锁定变量了。
每个变量用于不同的上下文。
清单 6 中显示了 spin_lock 和 spin_unlock 变量。
这是个最简单的变量,他不会执行中断禁用,不过包含全部的内存壁垒(memory barrier)。
这个变量假定中断处理程式和该锁之间没有交互。
清单 6. 自旋锁 lock 和 unlock 函数spin_lock( &my_spinlock );// critical sectionspin_unlock( &my_spinlock );接下来是 irqsave 和 irqrestore 对,如清单 7 所示。
spin_lock_irqsave 函数需要自旋锁,并且在本地处理器(在 SMP 情形中)上禁用中断。
spin_unlock_irqrestore 函数释放自旋锁,并且(通过 flags 参数)恢复中断。
清单 7. 自旋锁变量,其中禁用了本地 CPU 中断spin_lock_irqsave( &my_spinlock, flags );// critical sectionspin_unlock_irqrestore( &my_spinlock, flags );spin_lock_irqsave/spin_unlock_irqrestore 的一个不太安全的变体是spin_lock_irq/spin_unlock_irq。