互斥锁用起来要简单得多啊!
同一个资源同一个时间只有一个访问者在进行访问,其他的访问者访问结束以后才可以访问这个资源。这就是互斥。
互斥锁和信号量值为1的情况很类似,但是互斥锁更简洁,更高效。不过在使用中需要注意的事项也就更多。
| 函数 | 描述 |
|---|---|
| DEFINE_MUTEX(name) | 定义并初始化一个互斥锁 |
| void mutex_init(mutex *lock) | 初始化互斥锁 |
| void mutex_lock(struct mutex *lock) | 上锁,如果不可以用则睡眠 |
| void mutex_unlock(struct mutex *lock) | 解锁 |
| void mutex_is_locked(struct mutex *lock) | 如果锁已经被使用则返回1, 否则访问0 |
1.在信号量和互斥锁做选择的时候优先考虑互斥锁再考虑信号量,只有在非常底层的代码中才优先考虑信号量。
2.因为互斥锁和信号量相比它更简洁更高效
static struct mutex mutexlock;
static int flag = 1;static int misc_init(void)
{
...mutex_init(&mutexlock); // 初始化互斥锁
...return 0;
}int misc_open(struct inode *inode,struct file *file)
{mutex_lock(&mutexlock);//加锁进入临界区if(flag != 1){mutex_unlock(&mutexlock);return -EBUSY;}flag = 0;mutex_unlock(&mutexlock);// 退出临界区printk("hello misc_open\n ");return 0;
}int misc_release(struct inode *inode,struct file *file)
{flag = 1; // 退出的时候标志位赋值1printk("hello misc_relaease bye bye \n ");return 0;
}
led.c
#include //初始化头文件
#include //最基本的文件,支持动态添加和卸载模块。
#include //包含了miscdevice结构的定义及相关的操作函数。
#include //文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)
#include //包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include //包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include //驱动要写入内核,与内核相关的头文件#include
#include #define GPIO_DR 0xfdd60000 //LED物理地址,通过查看原理图得知
unsigned int *vir_gpio_dr; //存放映射完的虚拟地址的首地址static struct mutex mutexlock;
static int flag = 1;int misc_open(struct inode *inode,struct file *file)
{mutex_lock(&mutexlock);//加锁进入临界区if(flag != 1){mutex_unlock(&mutexlock);return -EBUSY;}flag = 0;mutex_unlock(&mutexlock);// 退出临界区printk("hello misc_open\n ");return 0;
}int misc_release(struct inode *inode,struct file *file)
{flag = 1; // 退出的时候标志位赋值1printk("hello misc_relaease bye bye \n ");return 0;
}ssize_t misc_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{printk("misc_read\n ");return 0;
}ssize_t misc_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{ /*应用程序传入数据到内核空间,然后控制蜂鸣器的逻辑,在此添加*/// kbuf保存的是从应用层读取到的数据char kbuf[64] = {0};// copy_from_user 从应用层传递数据给内核层if(copy_from_user(kbuf,ubuf,size)!= 0) {// copy_from_user 传递失败打印printk("copy_from_user error \n ");return -1;}//打印传递进内核的数据//printk("kbuf is %d\n ",kbuf[0]); if(kbuf[0]==1) //传入数据为1 ,LED亮{*vir_gpio_dr = 0x80008000; }else if(kbuf[0]==0) //传入数据为0,LED灭*vir_gpio_dr = 0x80000000;return 0;
}//文件操作集
struct file_operations misc_fops={.owner = THIS_MODULE,.open = misc_open,.release = misc_release,.read = misc_read,.write = misc_write,
};
//miscdevice结构体
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};
static int misc_init(void)
{int ret;mutex_init(&mutexlock); // 初始化互斥锁//注册杂项设备ret = misc_register(&misc_dev);if(ret<0){printk("misc registe is error \n");}printk("misc registe is succeed \n");//将物理地址转化为虚拟地址vir_gpio_dr = ioremap(GPIO_DR,4);if(vir_gpio_dr == NULL){printk("GPIO_DR ioremap is error \n");return EBUSY;}printk("GPIO_DR ioremap is ok \n"); return 0;
}
static void misc_exit(void){//卸载杂项设备misc_deregister(&misc_dev);iounmap(vir_gpio_dr);printk(" misc gooodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
以上代码编译成.ko文件
app.c
#include
#include
#include
#include
#include int main(int argc,char *argv[])
{int fd;char buf[64] = {0};//定义buf缓存char val[1];char cnt = 0;//打开设备节点fd = open("/dev/hello_misc",O_RDWR);if(fd < 0){//打开设备节点失败perror("open error \n"); return fd;}printf("open ok!\n");sleep(10);close(fd);printf("close ok!\n");return 0;
}
以上代码编译成app.armelf执行文件
测试:
[root@RK356X:/opt]# insmod led.ko
[26650.797782] misc registe is succeed
[root@RK356X:/opt]# [26650.798927] GPIO_DR ioremap is ok[root@RK356X:/opt]# cp app.armelf app2.armelf
[root@RK356X:/opt]# ./app.armelf &
[root@RK356X:/opt]# open ok![root@RK356X:/opt]# ./app2.armelf
close ok!
[26699.611356] hello misc_open
[26699.611356]
[26709.61open ok!
2118] hello misc_relaease bye bye
[26709.612118]
close ok!
[26709.612209] hello misc_open
[26709.612209]
[1]+ Done ./app.armelf
上一篇:多种方式绘制简单的作废章