自旋锁:
和信号量不同的是自旋锁可在不能休眠的代码中使用,如中断处理例程。在正确使用时,自旋锁通常比信号量具有更高的性能。
如果锁可用,则锁定位被设置,代码继续进入临界区;相反则代码进入忙循环并重复检查锁,直到该锁可用。
所有自旋锁在本质上是不可中断的,一旦调用了spin_lock,在获得锁之前一直处于自旋状态。
自旋锁的实现由于linux所支持的架构不同而不同。
自旋锁的核心规则是:任何拥有自旋锁的代码必须是原子的。自旋锁不能休眠。
自旋锁必须在可能的最短时间内拥有。
头文件:<linux/spinlock.h>
初始化:
静态:spinlock_t lock;
动态:void spin_lock_init(spinlock_t *lock);
获取锁:
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
获得自旋锁之前禁止中断,先前的中断状态保存在flags中。
void spin_lock_irq(spinlock_t *lock);
确保释放自旋锁时应该启用中断时调用。
void spin_lock_bh(spinlock_t *lock);
获得锁之前禁止软件中断。
释放锁:
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
非阻塞自旋锁:
int spin_trylock(spinlock_t *lock);
int spin_trylock_bh(spinlock_t *lock);
获得自旋锁返回非零值,否则返回零。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/spinlock.h>
static int major = 277;
static int minor = 0;
static dev_t helloNum;
static struct class *helloClass = NULL;
static struct device *helloDev = NULL;
static spinlock_t lock;
int busyFlag = 0;
int hello_open(struct inode *pinode, struct file *pfile)
{
printk("hello_open, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
spin_lock(&lock);
if (1 == busyFlag)
{
spin_unlock(&lock);
return -EBUSY;
}
busyFlag = 1;
spin_unlock(&lock);
return 0;
}
int hello_release(struct inode *pinode, struct file *pfile)
{
printk("hello_release, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
busyFlag = 0;
return 0;
}
static struct file_operations hello_ops = {
.open = hello_open,
.release = hello_release,
};
static int hello_init(void)
{
int ret = 0;
printk("hello_init\n");
ret = register_chrdev( major, "hello", &hello_ops);
if(ret < 0)
{
printk("register_chrdev failed.\n");
return ret;
}
helloClass = class_create(THIS_MODULE, "hellocls");
if (IS_ERR(helloClass))
{
printk("class_create failed.\n");
ret = PTR_ERR(helloClass);
goto error_exit1;
}
helloNum = MKDEV(major,minor);
printk("major:%d, minor:%d\n", MAJOR(helloNum), MINOR(helloNum));
helloDev = device_create(helloClass, NULL, helloNum, NULL, "hello0");
if (IS_ERR(helloDev))
{
printk("device_create failed.\n");
ret = PTR_ERR(helloDev);
goto error_exit2;
}
return 0;
error_exit2:
class_destroy(helloClass);
error_exit1:
unregister_chrdev(major,"hello");
return ret;
}
static void hello_exit(void)
{
printk("hello_exit\n");
device_destroy(helloClass, helloNum);
class_destroy(helloClass);
unregister_chrdev(major,"hello");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
读取者/写入者自旋锁(了解):
运行任意数量的读取者进入临界区,但写入者必须互斥访问。
rwlock和rwsem类似。
头文件:<linux/spinlock.h>
初始化:
rwlock_init(rwlock_t *lock);
读取者:
void read_lock(rwlock_t *lock);
void read_lock_irqsave(rwlock_t *lock, unsigned long flags);
void read_lock_irq(rwlock_t *lock);
void read_lock_bh(rwlock_t *lock);
void read_unlock(rwlock_t *lock);
void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
void read_unlock_irq(rwlock_t *lock);
void read_unlock_bh(rwlock_t *lock);
注:没有read_trylock函数。
写入者:
void write_lock(rwlock_t *lock);
void write_lock_irqsave(rwlock_t *lock, unsigned long flags);
void write_lock_irq(rwlock_t *lock);
void write_lock_bh(rwlock_t *lock);
int write_trylock(rwlock_t *lock);
void write_unlock(rwlock_t *lock);
void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
void write_unlock_irq(rwlock_t *lock);
void write_unlock_bh(rwlock_t *lock);