Linux内核的竞态与并发——自旋锁实例

    本文为 Linux内核的竞态与并发(中断屏蔽、原子操作、自旋锁、信号量、互斥体的互斥机制) 中自旋锁的实例

    其它部分:
Linux内核的竞态与并发——原子操作实例
Linux内核的竞态与并发——信号量实例

自旋锁使用步骤

// 1)定义一个自旋锁变量: 
	spinlock_t btn_lock;
// 2) 初始化自旋锁 :  
	spin_lock_init(&btn_lock)
// 3) 获取自旋锁 (获取权利)
   spin_lock(&btn_lock);       //获取自旋锁不成功,原地自旋等待,直到锁被释放,获取成功才返回
   //或:
   int spin_trylock(&btn_lock);//不成功,直接返回一个错误信息,调试的时候可用,可以避免死锁
// 4) 访问共享资源
// 5) 释放自旋锁
   spin_unlock(&btn_lock);

    自旋锁还有很多衍生自旋锁:读锁 写锁 顺序锁 内核的大锁:

// 1)定义一个自旋锁变量: 
	spinlock_t btn_lock;
// 2) 初始化自旋锁 :  
	spin_lock_init(&btn_lock)
// 3) 获取自旋锁 (获取权利)
	unsigned long flags;
    spin_lock_irq(&lock);            // = spin_lock() + local_irq_disable()
    //或
    spin_lock_irqsave(&lock, flags); // = spin_lock() local_irq_save()
// 4) 访问共享资源
// 5) 释放自旋锁
   spin_unlock_irq(&lock);          // = spin_unlock()+ local_irq_enable()
   //或
   spin_unlock_irqrestore(&lock, flags); // = spin_unlock() + local_irq_restore()

实例

btn_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>

MODULE_LICENSE("GPL");

dev_t dev;
struct cdev btn_cdev;
struct class *cls = NULL;

int count = 1; //共享资源
spinlock_t btn_lock;    				//[1]. 定义一个自旋锁变量

int btn_open(struct inode *inode, struct file *filp)
{
    spin_lock(&btn_lock);              /*[3].获取自旋锁*/ 

    count--;							/*[4] 访问共享资源*/ 					
    if(count !=0 )
    {
        count++;
        spin_unlock(&btn_lock);      /*[5]. 释放自旋锁*/
        return -EBUSY;
    }
    
    spin_unlock(&btn_lock);          /*[5].释放自旋锁*/
    return 0;
}

int btn_close(struct inode *inode, struct file *filp)
{
    spin_lock(&btn_lock);
    count++;
    spin_unlock(&btn_lock);
    return 0;
}
struct file_operations btn_fops =
{
    .owner = THIS_MODULE,
    .open  = btn_open,
    .release = btn_close,
};

int __init btn_drv_init(void)
{
    alloc_chrdev_region(&dev, 100, 1, "mybuttons");        /*设备号的动态申请注册*/
    cdev_init(&btn_cdev, &btn_fops);                       /*初始化cdev*/
    cdev_add(&btn_cdev, dev, 1);                           /*注册cdev*/
    cls = class_create(THIS_MODULE, "buttons");            /*设备文件的自动创建*/
    device_create(cls, NULL, dev, NULL,"mybuttons");
  
    spin_lock_init(&btn_lock);                             /*2.初始化自旋锁*/
    return 0;
}

void __exit btn_drv_exit(void)
{
    /*销毁设备文件*/
    device_destroy(cls, dev);
    class_destroy(cls);

    /*注销cdev*/
    cdev_del(&btn_cdev);

    /*注销设备号*/
    unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);

Makefile

obj-m  += btn_drv.o
all:
       make -C /home/chuckchee/driver/kernel M=$(PWD) modules
       cp *.ko ../../rootfs
       arm-cortex_a9-linux-gnueabi-gcc test.c -o test
       cp test ../../rootfs
clean:
       make -C /home/chuckchee/driver/kernel M=$(PWD) clean

test.c应用测试代码

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd = open("/dev/mybuttons", O_RDWR);

    if(fd < 0)
    {
        perror("open failed:");
        return -1;
    }
    printf("open successed: using device 20s...\n");
    sleep(20);
    printf("close device\n");
    close(fd);
    return 0;
}

实验步骤:

① insmod btn_drv.ko //设备文件自动形成
② ./test
③ 远程登录:telnet 192.168.1.6
④ ./test
⑤ 结果一般是登录失败

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页