您的位置:首页 > 移动开发 > Android开发

Android深度探索:HAL与驱动开发学习笔记--并发控制之信号量&完成量

2017-09-28 08:57 661 查看
semaphore

使用方法和自旋锁类似,与自旋锁相同,只有得到信号量的进程才能执行临界区代码,但是与自旋锁不同的是当获取不到信号量时,进程不原地打转而是进入休眠等待状态。


1. 函数:

声明变量:

struct semaphore sem;

快捷方式:

DECLARE_MUTEX(name) /* 定义一个名为name的信号量并初始化为1 */
DECLARE_MUTEX_LOCKED(name) /* 定义一个名为name的信号量并初始化为0 */

信号量的初始化:

void sema_init(struct semaphore *sem,int val);

参数:

sem,信号量

val,信号量的数量

信号量的获取: --相当于PV操作中的 P 操作

void down(struct semaphore *sem);  -->深度睡眠(没有资源时深度睡眠,无法被唤醒,只有资源来时才醒,是睡眠等待)

int down_interruptible(struct semaphore *sem);  -->可以被唤醒(浅睡)

int down_trylock(struct semaphore *sem); --> 如果能获得,获得,并返回0,否则,返回非0

if(down_interruptible(&sem))

return -ERESTARTSYS;

信号量的释放: --相当于PV操作中的 V 操作

void up(struct semaphore *sem);


2. 使用格式:

/* 定义信号量 */
DECLARE_MUTEX(mount_sem);
down(&mount_sem); /* 获取信号量,保护临界区 */
...
critical section /* 临界区 */
...
up(&mount_sem); /* 释放信号量 */


3. 例子:

使用信号量实现只能被一个进程打开:

[cpp] view
plain copy

 

 

static DECLARE_MUTEX(xxx_lock); /* 定义互斥锁 */  

static int xxx_open(struct inode *inode, struct file *filp)  

{  

    ...  

    if(down_trylock(&xxx_lock)) /* 获取打开锁 */  

        return -EBUSY; /* 设备忙 */  

    ...  

    return 0; /* 成功 */  

}  

  

static int xxx_release(struct inode *inode, struct file *filp)  

{  

    up(&xxx_lock); /* 释放打开锁 */  

    return 0;  

}  

读和写实现互斥:

[cpp] view
plain copy

 

 

#include <linux/kernel.h>  

#include <linux/init.h>  

1eee0
#include <linux/fs.h>  

#include <linux/cdev.h>  

#include <asm/uaccess.h>  

#include <linux/semaphore.h>  

#include <linux/module.h>  

  

MODULE_LICENSE ("GPL");  

  

int hello_major = 250;  

int hello_minor = 0;  

int number_of_devices = 1;  

  

struct hello_device  

{  

    char data[128];  

    struct semaphore sem;  

    struct cdev cdev;  

} hello_device;  

  

static int hello_open (struct inode *inode, struct file *file)  

{  

    printk (KERN_INFO "Hey! device opened\n");  

  

    return 0;  

}  

  

static int hello_release (struct inode *inode, struct file *file)  

{  

    printk (KERN_INFO "Hmmm... device closed\n");  

  

    return 0;  

}  

  

ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp)  

{  

    ssize_t result = 0;  

  

    if (count > 127) count = 127;  

  

    if (down_interruptible(&hello_device.sem))   

        return -EINTR;  

  

    if (copy_to_user (buff, hello_device.data, count))   

    {  

        result = -EFAULT;  

    }  

    else  

    {  

        printk (KERN_INFO "wrote %d bytes\n", count);  

        result = count;  

    }  

    up(&hello_device.sem);  

  

    return result;  

}  

  

ssize_t hello_write (struct file *filp, const char  *buf, size_t count, loff_t *f_pos)  

{  

    ssize_t ret = 0;  

  

    if (count > 127) return -ENOMEM;  

      

    if (down_interruptible(&hello_device.sem)) return -EINTR;  

  

    if (copy_from_user (hello_device.data, buf, count)) {  

        ret = -EFAULT;  

    }  

    else {  

        hello_device.data[count] = '\0';  

        printk (KERN_INFO"Received: %s\n", hello_device.data);  

        ret = count;  

    }  

    up(&hello_device.sem);  

  

    return ret;  

}  

  

  

struct file_operations hello_fops = {  

    .owner = THIS_MODULE,  

    .open  = hello_open,  

    .release = hello_release,  

    .read  = hello_read,  

    .write = hello_write  

};  

  

static void char_reg_setup_cdev (void)  

{  

    int error;  

    dev_t devno;  

  

    devno = MKDEV (hello_major, hello_minor);  

    cdev_init (&hello_device.cdev, &hello_fops);  

    hello_device.cdev.owner = THIS_MODULE;  

    error = cdev_add (&hello_device.cdev, devno , 1);  

    if (error)  

        printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);  

}  

  

static int __init hello_2_init (void)  

{  

    int result;  

    dev_t devno;  

  

    devno = MKDEV (hello_major, hello_minor);  

    result = register_chrdev_region (devno, number_of_devices, "hello");  

  

    if (result < 0) {  

        printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);  

        return result;  

    }  

  

    char_reg_setup_cdev ();  

    //init_MUTEX(&hello_device.sem);  for version not more than 2.6.35  

    sema_init(&hello_device.sem, 1);  

    printk (KERN_INFO "char device registered\n");  

  

    return 0;  

}  

  

static void __exit hello_2_exit (void)  

{  

    dev_t devno = MKDEV (hello_major, hello_minor);  

  

    cdev_del (&hello_device.cdev);  

  

    unregister_chrdev_region (devno, number_of_devices);  

}  

  

module_init (hello_2_init);  

module_exit (hello_2_exit);  


4. 信号量可以用于同步:

同步:一个执行单元的继续执行需要等待另一个执行单元完成某事,保证执行的顺序

步骤:

信号量被初始化为0
执行单元 A 中 down(&sem) (这里等待 B 中完成到 up()&sem)
执行单元 B 中 up(&sem)


5. 更好的实现同步的方法:完成量

一个执行单元等待另一个执行单元执行完某事:

函数如下:

定义:

struct completion my_completion;

初始化:

init_completion(&my_completion);

定义和初始化:

DECLARE_COMPLETION(my_completion);

等待完成量: -- 等待一个完成量的唤醒

void wait_for_compleition(struct completion *c);

唤醒完成量:

void complete(struct completion *c); --> 唤醒一个等待的执行单元
void complete_all(struct completion *c); --> 释放所有等待同一完成量的执行单元

使用方法:

前者只使唤一个等待的执行单元,后者释放所有等待统一完成量的执行单元


6. 读写信号量:

读写信号量可能引起进程阻塞,它允许 N 个读执行单元同时访问共享资源,最多只能有 1 个写执行单元

函数如下:

读写信号量定义和初始化:

struct rw_semaphore my_rws; /* 定义 */
void init_rwsem(struct rw_semaphone *sem); /* 初始化 */

读信号获取:

void down_read(struct rw_semaphore *sem);

int down_read_trylock(struct rw_semaphore *sem);

读信号量释放:

void up_read(struct rw_semaphore *sem);

写信号量获取:

void down_write(struct rw_semaphore *sem);

int down_write_trylock(struct rw_semaphore *sem);

写信号量释放:

void up_write(struct rw_semaphore *sem);

使用格式:

rw_semaphore rw_sem;
init_rwsem(&rw_sem);

/* 读时获取信号 */

down_read(&rw_sem);

...

up_read(&rw_sem);

/* 写时获取信号 */

down_write(&rw_sem);

...

up_write(&rw_sem);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: