linux驱动中的互斥途径四:信号量、完成量

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. 例子:

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

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;
}

读和写实现互斥:
#include <linux/kernel.h>
#include <linux/init.h>
#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. 信号量可以用于同步:

同步:一个执行单元的继续执行需要等待另一个执行单元完成某事,保证执行的顺序
步骤:
  1. 信号量被初始化为0
  2. 执行单元 A 中 down(&sem) (这里等待 B 中完成到 up()&sem)
  3. 执行单元 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);


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值