互斥体mutex
参考资料:
《正点原子Linux驱动教程》
《宋宝华 Linux设备驱动开发详解》
将信号量的值设置为 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 的时候要注意如下几点:
1、mutex 可以导致休眠,因此不能在中断中使用 mutex,中断中只能使用自旋锁。
2、和信号量一样,mutex 保护的临界区可以调用引起阻塞的 API 函数。
3、因为一次只有一个线程可以持有 mutex,因此,必须由 mutex 的持有者释放 mutex。并且 mutex 不能递归上锁和解锁。
互斥体的相关API:
互斥体的使用方法:
struct mutex lock; /* 定义一个互斥体 */ mutex_init(&lock); /* 初始化互斥体 */ mutex_lock(&lock); /* 上锁 */ /* 临界区 */ mutex_unlock(&lock); /* 解锁 */
互斥体使用测试demo:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/mutex.h> #define DEVICE_NAME "mutex_example" #define BUF_LEN 80 static int major_number; static char msg[BUF_LEN]; static short size_of_message; static struct class* char_class = NULL; static struct device* char_device = NULL; static DEFINE_MUTEX(mutex_lock); // 定义互斥体 static int dev_open(struct inode *inodep, struct file *filep){ if(!mutex_trylock(&mutex_lock)) { printk(KERN_ALERT "Mutex is in use by another process"); return -EBUSY; } return 0; } static int dev_release(struct inode *inodep, struct file *filep){ mutex_unlock(&mutex_lock); return 0; } static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){ int error_count = 0; error_count = copy_to_user(buffer, msg, size_of_message); return (error_count==0) ? 0 : -EFAULT; } static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){ sprintf(msg, "%s", buffer); size_of_message = strlen(msg); return len; } static struct file_operations fops = { .open = dev_open, .read = dev_read, .write = dev_write, .release = dev_release, }; static int __init mutex_example_init(void){ major_number = register_chrdev(0, DEVICE_NAME, &fops); if (major_number<0){ printk(KERN_ALERT "Failed to register a major number\n"); return major_number; } printk(KERN_INFO "Registered correctly with major number %d\n", major_number); char_class = class_create(THIS_MODULE, DEVICE_NAME); char_device = device_create(char_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME); mutex_init(&mutex_lock); return 0; } static void __exit mutex_example_exit(void){ mutex_destroy(&mutex_lock); device_destroy(char_class, MKDEV(major_number, 0)); class_unregister(char_class); class_destroy(char_class); unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_INFO "Goodbye from the mutex example driver!\n"); } module_init(mutex_example_init); module_exit(mutex_example_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203"); MODULE_DESCRIPTION("mutex demo");