学习笔记六:linux驱动之互斥锁mutex

互斥锁mutex

互斥体概述

信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mutex用于互斥操作。

mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,mutex比信号量执行速度更快,可扩展性更好,另外mutex数据结构的定义比信号量小。

互斥锁使用注意事项:
1.同一时刻只有一个线程可以持有mutex。
2.只有锁持有者可以解锁,不能在一个进程中持有mutex,在另外一个进程中释放他。
3.不允许递归地加锁和解锁。
4.当进程持有mutex时,进程不可以退出。
5.mutex必须使用官方API来初始化。
6.mutex可以睡眠,所以不允许在中断处理程序或者中断下半部中使用,例如tasklet、定时器

定义在linux/mutex.h中

struct mutex {
	atomic_t		count;
	spinlock_t		wait_lock;
	struct list_head	wait_list;
	...
};
// 定义互斥锁
mutex_init(struct mutex *lock);
DEFINE_MUTEX(name);
// 为指定的mutex加锁,如果不可用则睡眠
mutex_lock(struct mutex *lock);
// 为指定的mutex加锁,可中断
mutex_lock_interruptible(struct mutex *lock);
// 为指定的mutex加锁,可kill
mutex_lock_killable(struct mutex *lock);
// 为指定的mutex解锁
mutex_unlock(struct mutex *lock);
// 尝试获取指定的mutex,成功返回1,否则返回0并不会睡眠
mutex_trylock(struct mutex *lock);
// 判断锁是否被使用,如果被使用返回1,否则返回0
mutex_is_locked(struct mutex *lock);

示例代码:
驱动模块mmutex.c代码,为啥两个mm,因为一个m很多内容回合内核中的名字冲突,踩过坑了。

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEV_NAME    "mutex_test"
#define DEV_NUM     (1)

static struct my_st
{
    int major;
    int minor;
    dev_t dev_num;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct mutex lock;
}*my;


static int mmutex_open(struct inode *inode,struct file *filp)
{
    mutex_lock(&my->lock);
    printk("已上锁\r\n");
    return 0;
}

static int mmutex_release(struct inode *inode,struct file *flip)
{
    mutex_unlock(&my->lock);
    printk("已解锁\r\n");
    return 0;
}


static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = mmutex_open,
    .release = mmutex_release,
};


static int __init mmutex_init(void)
my = kzalloc(sizeof(struct my_st),GFP_KERNEL);
    if(my == NULL)
        return -ENOMEM;
    int ret = alloc_chrdev_region(&my->dev_num,DEV_NUM,0,DEV_NAME);
    if(ret < 0)
        goto alloc_chrdev_failed;
    my->major = MAJOR(my->dev_num);
    my->minor = MINOR(my->dev_num);

    cdev_init(&my->cdev,&fops);
    my->cdev.owner = THIS_MODULE;
    ret = cdev_add(&my->cdev,my->dev_num,DEV_NUM);
    if(ret < 0)
        goto cdev_add_failed;
    my->class = class_create(THIS_MODULE,DEV_NAME);
    if(IS_ERR(my->class))
    {
        ret = PTR_ERR(my->class);
        goto class_create_failed;
    }

    my->device = device_create(my->class,NULL,my->dev_num,NULL,DEV_NAME);
    if(IS_ERR(my->device))
    {
        ret = PTR_ERR(my->device);
        goto device_create_failed;
    }

    printk("mutex device is ok \r\n");
    printk("主设备号:%d\r\n",my->major);

    mutex_init(&my->lock);

    return 0;
device_create_failed:
    class_destroy(my->class);
class_create_failed:
    cdev_del(&my->cdev);
cdev_add_failed:
    unregister_chrdev_region(my->dev_num,DEV_NUM);
alloc_chrdev_failed:
    kfree(my);
    return ret;
}

static void __exit mmutex_exit(void)
{
    device_destroy(my->class,my->dev_num);
    class_destroy(my->class);
    cdev_del(&my->cdev);
    unregister_chrdev_region(my->dev_num,DEV_NUM);
    kfree(my);
    printk("mutex device was removed\r\n");
}

module_init(mmutex_init);
module_exit(mmutex_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chen");

Makefile

ifneq ($(KERNELRELEASE),)
    obj-m:=mmutex.o
else
    CURRENT_DIR:=$(shell pwd)
    KERNEL_DIR:=/lib/modules/$(shell uname -r)/build
    ccflags-y:=-std=gnu99 -Wdeclaration-after-statement
all:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
clean:
    $(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
endif

下面是测试的app,先让一个终端执行.app,再让另一个终端也执行这个app,会发现在第一个app进行close后第二个app才可以open才可以成功,因为当第一个app执行open后获得了mutex锁,并且未释放。第二个app进行open时会由于第一个app未释放锁而进入睡眠状态。当第一个进程释放锁后第二进程才可以获得锁。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd = open("/dev/mutex_test",O_RDWR);
    if(fd < 0 ) 
    {   
        perror("");
        exit(1);
    }   
    printf("before sleep\r\n");
    sleep(15);
    printf("after sleep\r\n");

    close(fd);
    exit(0);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值