ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux驱动之互斥量

2022-02-23 20:01:19  阅读:176  来源: 互联网

标签:__ struct pthread 互斥 leddev mutex Linux 驱动


Linux内核中的互斥锁跟信号量一样,是内核中实现进程的同步与互斥的机制。不同的是信号量可以实现多个进程同时访问共享资源,但是互斥锁只允许一个进程访问共享资源。
互斥锁的相关函数

// 互斥锁结构体,省略宏定义相关的参数
struct mutex {
	/* 1: unlocked, 0: locked, negative: locked, possible waiters */
	atomic_t		count;  // 互斥锁计数
	spinlock_t		wait_lock; // 自旋锁
	struct list_head	wait_list;  // 互斥量等待队列
	......................
};

// 互斥锁初始化宏定义
# define mutex_init(mutex) \
do {							\
	static struct lock_class_key __key;		\
							\
	__mutex_init((mutex), #mutex, &__key);		\
} while (0)

void mutex_lock(struct mutex *lock);  // 获取互斥锁,如果获取不到就睡眠,不可被打断
int __must_check mutex_lock_interruptible(struct mutex *lock);// 获取互斥锁,如果获取不到就睡眠,可被打断
int mutex_trylock(struct mutex *lock); // 尝试获取互斥锁,获取成功返回1,否则返回0,不进入睡眠
void mutex_unlock(struct mutex *lock);  // 释放互斥锁

接下来编写驱动程序和应用程序来进行互斥锁的测试、
驱动程序

#define CHRDEV_MAJOR 240  // 主设备号
#define CHRDEV_MAION 0    // 次设备号
#define CHRDEV_COUNT 1    // 次设备号个数
#define CHRDEV_NAME  "testchrdev"

struct led_cdev
{
	struct cdev chrdevcdev;
	int major;
	dev_t dev;
	struct class *led_dev_class;
	struct mutex led_mutex;  // 定义互斥锁
};
static struct led_cdev leddev;



ssize_t chrdev_read (struct file *file, char __user *usr, size_t size, loff_t *loff)
{
	
	return 0;
}
int chrdev_open (struct inode *inode, struct file *file)
{
	if (!mutex_trylock(&leddev.led_mutex)) {  // 当应用程序打开文件时会尝试获取互斥锁
		return -EBUSY;                         // 当互斥锁已经获取完时,就返回错误码
	}
	file->private_data = &leddev;
	return 0;
}
int chrdev_release (struct inode *inode, struct file *file)
{
	struct led_cdev  *led_private_data = (struct led_cdev  *)file->private_data;
	mutex_unlock(&led_private_data->led_mutex);  // 释放互斥锁
	return 0;
}
struct file_operations fops = 
{
	.open    = chrdev_open,
	.read    = chrdev_read,
	.release = chrdev_release,
};


static int __init chrdev_init(void)
{
	int ret = 0,error = 0;
	struct device *devices;
	//DEBUG_SFLR("%s\r\n",__func__);
	error = alloc_chrdev_region(&leddev.dev,CHRDEV_MAION,CHRDEV_COUNT,CHRDEV_NAME); // 注册设备号
	printk("MAJOR = %d MINOR = %d\r\n",MAJOR(leddev.dev),MINOR(leddev.dev));
	if(error < 0){
		printk("alloc_chrdev_region error\r\n");
		ret =  -EBUSY;
		goto fail;
	}
	leddev.major = MAJOR(leddev.dev);
	cdev_init(&leddev.chrdevcdev, &fops); // 绑定字符设备操作函数集
	error = cdev_add(&leddev.chrdevcdev,leddev.dev,CHRDEV_COUNT);   // 添加字符设备
	if(error < 0){
		printk("cdev_add error\r\n");
		ret =  -EBUSY;
		goto fail1;
	}
	
	// 创建类,类名为testledclass
	leddev.led_dev_class = class_create(THIS_MODULE, "testledclass");
	if (IS_ERR(leddev.led_dev_class)){
		printk("class_create error\r\n");
		ret =  -EBUSY;
		goto fail2;
	}
		
	// 创建设备
	devices = device_create(leddev.led_dev_class, NULL, MKDEV(leddev.major,0), NULL, "testled");
	if(NULL == devices){
		printk("device_create error\r\n");
		ret =  -EBUSY;
		goto fail3;
	}
	
	
	mutex_init(&leddev.led_mutex);   // 初始化互斥锁
	
	return 0;
fail3:	
	class_destroy(leddev.led_dev_class);/*  删除类 */
	
fail2:	
	cdev_del(&leddev.chrdevcdev);/*  删除cdev */
fail1:
	unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
fail:
	return ret;
}


static void __exit chrdev_exit(void)
{
	//DEBUG_SFLR("%s\r\n",__func__);
	device_destroy(leddev.led_dev_class,MKDEV(leddev.major,0));/*  卸载设备 */
	class_destroy(leddev.led_dev_class);/*  删除类 */
	cdev_del(&leddev.chrdevcdev);/*  删除cdev */
	unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
}

module_init(chrdev_init);
module_exit(chrdev_exit);

MODULE_DESCRIPTION("xxxxxx");
MODULE_AUTHOR("xxxxxx");
MODULE_LICENSE("GPL");

在驱动程序中,第83行调用mutex_init进入互斥锁的初始化。在chrdev_open 函数中调用mutex_trylock尝试获取互斥锁,如果获取失败就返回错误代码给应用程序。在chrdev_release调用mutex_unlock释放互斥锁。

应用程序

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

#define FILE_NAME "/dev/testled"

void *pthread_func1 (void *arg)
{
	
	int fd = -1;
	fd = open(FILE_NAME,O_RDONLY);
	if(fd < 0){
		printf("%s open %s error\r\n",__func__,FILE_NAME);
		pthread_exit(0);
	}
	printf("%s open %s success\r\n",__func__,FILE_NAME);
	sleep(5);
	
	close(fd);
	pthread_exit(0);
}

void *pthread_func2(void *arg)
{
	
	int fd = -1;
	
	while(1)
	{
		fd = open(FILE_NAME,O_RDONLY);
		if(fd < 0){
		printf("%s open %s error\r\n",__func__,FILE_NAME);
			
		}
		if(fd > 0)
		{
			break;
		}
		sleep(1);
	}
	printf("%s open %s success\r\n",__func__,FILE_NAME);
	close(fd);
	pthread_exit(0);
}
int main(void)
{
	pthread_t pth1,pth2;
	int err = 0;
	
	pthread_create(&pth1,NULL,pthread_func1,NULL);
	sleep(1);
	pthread_create(&pth2,NULL,pthread_func2,NULL);
	while(1);
	return 0;
}

在应用程序的main函数中先创建2条线程。pthread_func1会先运行并打开设备文件,然后等5秒后再关闭设备文件。pthread_func2后运行,pthread_func2会进入死循环并每隔一秒就尝试打开设备文件,当文件打开成功就退出循环并关闭文件。将驱动程序和应用程序编译完之后放到开发板中运行。
在这里插入图片描述
通过结果可以看到,首先pthread_func1先运行并打开文件成功,pthread_func2后运行打开了4次文件都失败,第5次打开成功。这时因为当pthread_func1打开设备文件时,互斥锁已经被申请了,此时互斥锁的计数值为0,当pthread_func2想打开设备文件时,已经没可用的互斥锁了,所以就导致设备文件打开失败。当pthread_func1关闭文件时,释放了互斥锁,此时pthread_func2打开设备文件并获取互斥锁成功。所以互斥锁申请完之后记得要释放。

标签:__,struct,pthread,互斥,leddev,mutex,Linux,驱动
来源: https://blog.csdn.net/hwx1546/article/details/123097369

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有