在 FreeRTOS 和 UCOS 中也有互斥体,将信号量的值设置为 1 就可以使用信号量进行互斥访问了,虽然可以通过信号量实现互斥,但是 Linux 提供了一个比信号量更专业的机制来进行互斥,它就是互斥体—mutex。互斥访问表示一次只有一个线程可以访问共享资源,不能递归申请互斥体。在我们编写 Linux 驱动的时候遇到需要互斥访问的地方建议使用 mutex。 Linux 内核 使用 mutex 结构体表示互斥体,定义如下(省略条件编译部分):
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
spinlock_t wait_lock;
};
在使用 mutex 之前要先定义一个 mutex 变量。在使用 mutex 的时候要注意如下几点:
①、 mutex 可以导致休眠,因此不能在中断中使用 mutex,中断中只能使用自旋锁。
②、和信号量一样, mutex 保护的临界区可以调用引起阻塞的 API 函数。
③、因为一次只有一个线程可以持有 mutex,因此,必须由 mutex 的持有者释放 mutex。并且 mutex 不能递归上锁和解锁。
#include <linux/types.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/device.h>
#define CHRDEVBASE_MAJOR 200
uint8_t kernel_buffer[1024] = {0};
static struct class *hello_class;
struct mutex lock;
static int hello_world_open(struct inode * inode, struct file * file)
{
printk("hello_world_open\r\n");
/* 获取信号量 */
if (mutex_lock_interruptible(&lock)) {
return -ERESTARTSYS;
}
printk("hello_world_open success\r\n");
return 0;
}
static int hello_world_release (struct inode * inode, struct file * file)
{
printk("hello_world_release\r\n");
mutex_unlock(&lock);
return 0;
}
static const struct file_operations hello_world_fops = {
.owner = THIS_MODULE,
.open = hello_world_open,
.release = hello_world_release,
.read = NULL,
.write = NULL,
};
static int __init hello_driver_init(void)
{
int ret;
printk("hello_driver_init\r\n");
mutex_init(&lock);
ret = register_chrdev(CHRDEVBASE_MAJOR,"hello_driver",&hello_world_fops);
hello_class = class_create(THIS_MODULE,"hello_class");
device_create(hello_class,NULL,MKDEV(CHRDEVBASE_MAJOR,0),NULL,"hello"); /* /dev/hello */
return 0;
}
static void __exit hello_driver_cleanup(void)
{
printk("hello_driver_cleanup\r\n");
device_destroy(hello_class,MKDEV(CHRDEVBASE_MAJOR,0));
class_destroy(hello_class);
unregister_chrdev(CHRDEVBASE_MAJOR,"hello_driver");
}
module_init(hello_driver_init);
module_exit(hello_driver_cleanup);
MODULE_LICENSE("GPL");