linux驱动18:信号量(内核)

一个信号量本质上是一个整数值,它和一对函数联合使用,P(-1)和V(+1)。内核中的信号量通常用于互斥;用于互斥时,信号量的值初始化为1,用于同步时初始化为0。

内核使用信号量包含<linux/semaphore.h>,相关的类型为struct semaphore。

信号量初始化:

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

val:信号量的初始值

P函数:

int down(struct semaphore *sem);  

减小信号量的值,并在必要时一直等待,不可中断。

int down_interruptible(struct semaphore *sem); //建议使用

减小信号量的值,并在必要时一直等待,但是操作是可以中断的,允许等待在某个信号量上的用户空间进程可被用户中断(如:ctrl+c)。如果返回非零值,表示操作被中断,应返回-ERESTARTSYS。

int down_trylock(struct semaphore *sem); 

不会休眠,如果信号量在调用时不可获得会立即返回一个非零值。

当某个线程或进程P后,表示拥有信号量,即拥有访问该信号量保护的临界区的权利。

V函数:

void up(struct semaphore *sem);

当互斥操作完后,必须返回该信号量,调用up后,调用者不再拥有信号量。

#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/uaccess.h>
#include <linux/semaphore.h> 

static int major = 277;
static int minor = 0;
static dev_t devnum1;
static struct cdev cdev1;
struct semaphore sem; 

int hello_open(struct inode *pinode, struct file *pfile)
{
	printk("hello_open, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
	if(down_interruptible(&sem))
	{
		return -ERESTARTSYS;
	}	
	return 0;
}

int hello_release(struct inode *pinode, struct file *pfile)
{
	printk("hello_release, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
	up(&sem);
	return 0;
}

ssize_t hello_read(struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
	return 0;
}

ssize_t hello_write(struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
/*
    if(down_interruptible(&sem))
	{
		return -ERESTARTSYS;
	}
    
    ...
    copy_from_user();
    ...

    up(&sem);
*/
	return 0;
}

static struct file_operations hello_ops = {
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
};

static int hello_init(void)
{
	printk("hello_init\n");
	devnum1 = MKDEV(major,minor);
	printk("major:%d, minor:%d\n", MAJOR(devnum1), MINOR(devnum1));
	if (register_chrdev_region(devnum1, 1, "hello1"))//分配设备号
	{
		printk("register_chrdev_region failed\n");
		return -1;
	}

	cdev_init(&cdev1, &hello_ops);//初始化cdev,绑定fops
	if (cdev_add(&cdev1, devnum1, 1) < 0)//添加设备到内核
	{
		printk("cdev_add failed\n");
		unregister_chrdev_region(devnum1, 1);
		return -1;
	}
	
	sema_init(&sem,1);//初始化信号量,值为1,用于互斥

	return 0;
}

static void hello_exit(void)
{
	printk("hello_exit\n");
	cdev_del(&cdev1);
	unregister_chrdev_region(devnum1, 1);
}

MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char * argv [ ])
{
	int fd = open("/dev/hello0", O_RDWR, 666);
	if (fd < 0)
	{
		perror("open faied");
		return -1;
	}

	printf("open successed: %d\n", fd);

	sleep(10);
	printf("close %d\n", fd);
	close(fd);
	return 0;
}

实现同一时间只能打开一个设备。

现象:运行两个demo,先运行的demo占有信号量,在sleep的过程中ctrl+c可中断,后运行的demo获取信号量。

还可以实现write互斥,同一时间只能允许一个调用者进行写操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值