栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux驱动学习记录-9.并发与竞争实验

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux驱动学习记录-9.并发与竞争实验

本章实验由第六章“设备树led驱动”代码修改而来,设备树不需要改动。

文章目录
  • 一、原子操作
    • 1.驱动程序
    • 2.测试
  • 二、自旋锁实验
    • 1.驱动程序
    • 2.测试
  • 三、信号量
    • 1.驱动程序
    • 2.测试
  • 四、互斥体实验
    • 1.驱动程序
    • 2.测试
  • 五、总结


一、原子操作 1.驱动程序

实现一次只能操作一个led,当这个驱动正在操作这个led时,其他驱动不可访问这个led。
思路:在设备结构体定义一个原子整形变量,并在入口函数初始化为1,在使用open打开驱动的时候,先检查原子变量的值是否为1,是的话减一并设置私有数据,驱动正常运行。如果不是1,代表驱动在被占用,返回APP文件,打开驱动失败。在关闭设备函数release里要释放原子变量,加一。
以下程序修改自gpioled.c,撷取部分。

struct gpioled_dev{
	dev_t devid;			
	struct cdev cdev;		
	struct class *class;	
	struct device *device;	
	int major;				
	int minor;				
	struct device_node	*nd; 
	int led_gpio;			
	atomic_t num;           
};
struct gpioled_dev gpioled;

static int led_open(struct inode *inode, struct file *filp)
{
	if(atomic_dec_and_test(&gpioled.num)){ 
		filp->private_data = &gpioled; 
		return 0;
	}
	else{
		atomic_inc(&gpioled.num);
		return -1;
	}
}

static int led_release(struct inode *inode, struct file *filp)
{
	struct gpioled_dev *dev = filp->private_data;
	atomic_inc(&dev->num);
	return 0;
}

static int __init led_init(void)
{
	atomic_set(&gpioled.num, 1);
	
	
	
	return 0;
}

2.测试
int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];

	filename = argv[1];

	
	fd = open(filename, O_RDWR);

	databuf[0] = atoi(argv[2]);	

	
	retvalue = write(fd, databuf, sizeof(databuf));
	
	while(1){
		sleep(5);//延迟5s
		cnt++;
		printf("App running times:%drn", cnt);
		if(cnt >= 5) break; //5次 25s
	}
	retvalue = close(fd); 

	return 0;
}

在驱动程序卡在while时,还没close,原子变量还是0,再次执行APP,驱动无法打开。
执行ledApp时,输入&,可在后台运行程序,输入框仍可以用。

./ledApp /dev/led 1&
二、自旋锁实验 1.驱动程序

自旋锁保护的临界区尽可能短,因此在open函数加锁,release函数开锁不可取。思路:申请一个自旋锁标志位为1,在open函数判断flag是否为0,若是则返回负值,打开失败。若是1,则加锁,flag自减1,解锁。再设置私有数据。release函数加锁,flag自加1,解锁。

struct gpioled_dev{
	
	spinlock_t spinlock;	
	int flag;               
};
struct gpioled_dev gpioled;	
static int led_open(struct inode *inode, struct file *filp)
{
	unsigned long flag;
	spin_lock_irqsave(&gpioled.spinlock, flag);
	if(gpioled.flag == 0) {
		spin_unlock_irqsave(&gpioled.spinlock, flag);
		return -1;
	}
	gpioled.flag --;
	spin_unlock_irqsave(&gpioled.spinlock, flag);
	filp->private_data = &gpioled;
	return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
	spin_lock_irqsave(&gpioled.lock, flag);
	gpioled.flag = 1;
	spin_unlock_irqsave(&gpioled.spinlock, flag);
	return 0;
}
static int __init led_init(void)
{
	int ret = 0;
	unsigned long flag;
	spin_lock_init(&gpioled.lock);
	spin_lock_irqsave(&gpioled.lock, flag);
	gpioled.flag = 1;
	spin_unlock_irqsave(&gpioled.spinlock, flag);
	

	

	return 0;
}
2.测试

和前一节一样。

三、信号量 1.驱动程序

信号量导致休眠,因此信号量保护的临界区没有时间限制,可以在open函数申请信号量,release函数释放信号量。

#include 
struct gpioled_dev{
	
	struct semaphore sema;	
};

struct gpioled_dev gpioled;	
static int led_open(struct inode *inode, struct file *filp)
{
	if(down_trylock(&gpioled.sema))
		return -1;
	filp->private_data = &gpioled;
	return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
	struct gpioled_dev *dev = filp->private_data
	up(&dev->sema);
	return 0;
}
static int __init led_init(void)
{
	int ret = 0;
	sema_init(&gpioled.sema, 1);
	

	
	return 0;
}
2.测试

和上节一样。

四、互斥体实验 1.驱动程序

上一节信号量实验,把信号量设置为1,相当于互斥体,对于互斥建议使用专门的互斥体。

struct gpioled_dev{
	
	struct mutex mutex;	
};

struct gpioled_dev gpioled;	
static int led_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &gpioled;
	
	if(mutex_lock_interruptible(&gpioled.mutex))
		return -1;
	return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
	struct gpioled_dev *dev = filp->private_data
	mutex_unlock(&dev.mutex);
	return 0;
}
static int __init led_init(void)
{
	int ret = 0;
	mutex_init(&gpioled.mutex);
	

	
	return 0;
}
2.测试

和前一节一样。

五、总结

原子操作只能对整形使用,因此自旋锁和信号量应用较广泛。
自旋锁会导致死循环,锁定期间不允许阻塞,因此要求临界区小。信号量允许临界期大。互斥体是信号量为1的特殊情况。
读写自旋锁和读写信号量是条件放宽的自旋锁和信号量,它们允许多个执行单元对共享资源的并发读,但不能并发写。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/334317.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号