内核同步机制

来源:互联网 发布:数据库集群方案 编辑:程序博客网 时间:2024/05/22 07:04

linux 内核为了避免共享数据(临界区)访问冲突,提出了一些控制机制:原子量,自旋锁,信号量


原子量:

  • 原子操作:cpu 执行某个操作过程中,不可被外界打断或中断
  • 原子变量:原子量的运算过程不可被中断
  • 如何使用原子变量:

    1.定义原子量 :atomic_t xxx

    2.原子量操作函数:

atomic_set(&v, i)                                   //初始化atomic_read(v)                                      //读atomic_add(int i, volatile atomic_t *v)             //加,无返回值atomic_sub(int i, volatile atomic_t *v)             //减,无返回值int atomic_add_return(int i, volatile atomic_t *v)  //加int atomic_sub_return(int i, volatile atomic_t *v)  //减int atomic_cmpxchg(atomic_t *v, int old, int new)   //交换atomic_inc(v)                                       //自加atomic_dec(v)                                       //自减

自旋锁

如果一个进程给临界区加锁,后来的进程加速哦是加锁不成功,会发生阻塞,只到临界区被解锁,后来的进程解除阻塞,加锁成功,继续运行

  • 如何使用自旋锁

    1.定义自旋锁 :spinlock_t xxx

    2.初始化自旋锁:spin_lock_init(_lock)

    3.临界区前加锁:static inline void spin_lock(spinlock_t *lock)

    4.临界区后解锁:static inline void spin_unlock(spinlock_t *lock)


信号量

主要用于进程间同步,本质上是一个计数器,每当进程访问共享资源时,信号量做减一操作,如果信号量为0,后来的进程在做减一操纵不成功,会发生阻塞,知道信号量大于零,才解除阻塞,减一成功,继续执行

  • 如何使用信号量

    1.定义信号量:struct semaphore xxx

    2.初始化信号量:sema_init(struct semaphore *sem, int val)

    3.减一操作: down(struct semaphore *sem)

    4.加一操作:up(struct semaphore *sem)


示例代码:

#include <linux/kernel.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/kdev_t.h>#include <linux/device.h>#include <linux/io.h>#include <linux/uaccess.h>#include <linux/export.h>#include <linux/types.h>#include <linux/atomic.h>#include <linux/spinlock.h>#define GPM4CON 0x110002E0volatile unsigned long *baseaddr = 0;#define rGPM4CON (*((volatile unsigned long *)(baseaddr + 0)))#define rGPM4DAT (*((volatile unsigned long *)(baseaddr + 1)))#define MYLED_MAJOR 0#define MYLED_NAME "led"#define MYLED_DRVNUM 1#define MYLED_NUM 4dev_t myled_devt;       //设备号int myled_major;struct class *myled_class;      //设备结构体struct cdev *myled;             //设备驱动核心结构//atomic_t myled_atomic;  //原子操作/*//自旋锁操作int count;struct spinlock myled_spinlock;*/struct semaphore myled_semaphore;char led_status[MYLED_NUM]={-1,-1,-1,-1};loff_t led_lseek (struct file *fp, loff_t off, int whence){    loff_t newoff=0;    switch(whence)    {        case SEEK_SET:            newoff=off;            break;        case SEEK_CUR:            newoff = fp->f_pos+off;            break;        case SEEK_END:            newoff = 4 + off;        default:            return -EINVAL;    }    if(newoff<0)        newoff = 0;    else if(newoff>4)        newoff = 4;    fp->f_pos=newoff;    return newoff;}ssize_t led_read (struct file *fp, char __user *buf, size_t size, loff_t *off){    int i=0;    unsigned long ret;    if(*off>4)        return -EINVAL;    if(*off+size>4)        size = 4-*off;    for(i=0;i<MYLED_NUM;i++)        led_status[i]= !(rGPM4DAT&(0x1<<i));    ret = copy_to_user(buf,&led_status[*off],size);    *off = *off+size;    printk("led_read is called\n");    return 0;}ssize_t led_write (struct file *fp, const char __user *buf, size_t size, loff_t *off){    int i;    unsigned long temp;    if(*off>4)        return -EINVAL;    if(*off + size >4)        size = 4 - *off;    temp = copy_from_user(&led_status[*off],buf,size);    for(i=0;i<MYLED_NUM;i++)    {        if(led_status[i] == 0)            rGPM4DAT |= (0x1<<i);        else if(led_status[i] == 1)            rGPM4DAT &= ~(0x1<<i);        else            return -EINVAL;    }    *off = *off + size;    printk("led_write is called \n");    return 0;}int led_open (struct inode *node, struct file *fp){    int i=0;/*  //原子操作    if(myled_atomic.counter)    {        printk("this derive is being used \n");        return -EINVAL;    }    atomic_inc(&myled_atomic);*//*  //自旋锁    spin_lock(&myled_spinlock);    if(count)    {        printk("this device is being used \n");        spin_unlock(&myled_spinlock);        return -EINVAL;    }    count++;    spin_unlock(&myled_spinlock);*/    //信号量     down(&myled_semaphore);    fp->private_data =(void *) MINOR(node->i_rdev);    rGPM4CON &= ~(0xffff);    rGPM4CON |= (0x1111);    for(i=0;i<MYLED_NUM;i++)    {        led_status[i] = !(rGPM4DAT&(0x1<<i));    }    printk("led_open is called \n");    return 0;}int led_close (struct inode *node, struct file *fp){    printk("led_close is called \n");/*  //原子操作    if(myled_atomic.counter)        atomic_dec(&myled_atomic);*//*  //自旋锁    spin_lock(&myled_spinlock);    if(count)        count--;    spin_unlock(&myled_spinlock);*/    //信号量    up(&myled_semaphore);    return 0;}long led_ioctl(struct file *fp, unsigned int cmd, unsigned long arg){    int i=0;    if(_IOC_TYPE(cmd) != 'x')        return -EINVAL;    switch (_IOC_DIR(cmd))    {        case _IOC_READ:            for(i=0;i<MYLED_NUM;i++)            {                led_status[i] =! (rGPM4DAT&(0x1<<i));            }            if(copy_to_user((long*)arg,led_status,4))                return -EINVAL;            break;        case  _IOC_WRITE:            if(_IOC_NR(cmd)==0)                rGPM4DAT |= (0x1<<arg);            else if(_IOC_NR(cmd) == 1)                rGPM4DAT &= ~(0x1<<arg);            else                return -EINVAL;            break;        case (_IOC_WRITE|_IOC_READ):        {            for(i=0;i<MYLED_NUM;i++)                led_status[i]=! (rGPM4DAT&(0x1<<i));            switch (_IOC_NR(cmd))            {                case 0:                    rGPM4DAT |= (0x1<<*((int *)arg));                    break;                case 1:                    rGPM4DAT &= ~(0x1<<*((int *)arg));                    break;                default :                    return -EINVAL;                    break;            }            if(copy_to_user((long*)arg,led_status,MYLED_NUM))                return -EINVAL;            break;        }        case _IOC_NONE:            break;        default:            break;    }    return 0;}struct file_operations led_fops={    .owner=THIS_MODULE,    .open =led_open,    .release = led_close,    .read=led_read,    .write = led_write,    .unlocked_ioctl= led_ioctl,    .llseek = led_lseek,};static int __init myled_init(void){    int i=0;    //原子操作//  atomic_set(&myled_atomic,0);/*  //自旋锁    spin_lock_init(&myled_spinlock);    count=0;*/    //信号量    sema_init(&myled_semaphore,1);#if MYLED_MAJOR    myled_major = MYLED_MAJOR;    myled_devt = MKDEV(myled_major,0);    if(register_chrdev_region(myled_devt,MYLED_DRVNUM,MYLED_NAME))#else    if(alloc_chrdev_region(&myled_devt,0,MYLED_DRVNUM,MYLED_NAME))#endif    {        printk("注册失败\n");        return -EBUSY;    }    myled = cdev_alloc();    cdev_init(myled,&led_fops);    if(cdev_add(myled,myled_devt,MYLED_DRVNUM))        {        printk("注册成功\n");        return -EBUSY;    }    printk("注册成功\n");    myled_class = class_create(THIS_MODULE,MYLED_NAME);    for(i=0;i<MYLED_DRVNUM;i++)        device_create(myled_class,NULL,myled_devt+i,NULL,"myled%d",i);    baseaddr = ioremap(GPM4CON, 8);    return 0;}static void __exit myled_exit(void){    iounmap(baseaddr);    device_destroy(myled_class, myled_devt);    class_destroy(myled_class);    cdev_del(myled);    unregister_chrdev_region(myled_devt,MYLED_DRVNUM);    printk("注销成功\n");}module_init(myled_init);module_exit(myled_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("MOMO");
原创粉丝点击