在 FreeRTOS 和 UCOS 中也有互斥體,將信號(hào)量的值設(shè)置為 1 就可以使用信號(hào)量進(jìn)行互斥訪問了,雖然可以通過信號(hào)量實(shí)現(xiàn)互斥,但是 Linux 提供了一個(gè)比信號(hào)量更專業(yè)的機(jī)制來進(jìn)行互斥,它就是互斥體—mutex。互斥訪問表示一次只有一個(gè)線程可以訪問共享資源,不能遞歸申請(qǐng)互斥體。在我們編寫 Linux 驅(qū)動(dòng)的時(shí)候遇到需要互斥訪問的地方建議使用 mutex。 Linux 內(nèi)核 使用 mutex 結(jié)構(gòu)體表示互斥體,定義如下(省略條件編譯部分):
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
spinlock_t wait_lock;
};
在使用 mutex 之前要先定義一個(gè) mutex 變量。在使用 mutex 的時(shí)候要注意如下幾點(diǎn):
①、 mutex 可以導(dǎo)致休眠,因此不能在中斷中使用 mutex,中斷中只能使用自旋鎖。
②、和信號(hào)量一樣, mutex 保護(hù)的臨界區(qū)可以調(diào)用引起阻塞的 API 函數(shù)。
③、因?yàn)橐淮沃挥幸粋€(gè)線程可以持有 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");
/* 獲取信號(hào)量 */
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");