设备驱动技术实验五Word格式.docx
《设备驱动技术实验五Word格式.docx》由会员分享,可在线阅读,更多相关《设备驱动技术实验五Word格式.docx(11页珍藏版)》请在冰点文库上搜索。
![设备驱动技术实验五Word格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/6/66a5e77a-6f4c-48ae-8485-4eae2273b0f7/66a5e77a-6f4c-48ae-8485-4eae2273b0f71.gif)
1、实验内容与要求:
1)原子操作;
2)自旋锁;
3)信号量、互斥体机制。
2、实验安排方式:
采用1人1组,上机在Linux系统下进行编程实验。
三、实验设备
1、所用设备:
PC机一台
四、实验过程
所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。
原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。
原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。
原子类型定义如下:
volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。
原子操作API包括:
0.该函数对原子类型的变量进行原子读操作,它返回原子类型的变量v的值。
1.该函数设置原子类型的变量v的值为i
atomic_set(atomic_t*v,inti);
2.该函数给原子类型的变量v增加值i。
voidatomic_add(inti,atomic_t*v);
3.该函数从原子类型的变量v中减去i。
atomic_sub(inti,atomic_t*v);
4.该函数从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假。
intatomic_sub_and_test(inti,atomic_t*v);
5.该函数对原子类型变量v原子地增加1。
voidatomic_inc(atomic_t*v);
6.该函数对原子类型的变量v原子地减1
voidatomic_dec(atomic_t*v);
7.该函数对原子类型的变量v原子地减1,并判断结果是否为0,如果为0,返回真,否则返回假。
intatomic_dec_and_test(atomic_t*v);
8.该函数对原子类型的变量v原子地增加1,并判断结果是否为0,如果为0,返回真,否则返回假。
intatomic_inc_and_test(atomic_t*v);
9.该函数对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假。
intatomic_add_negative(inti,atomic_t*v);
10.该函数对原子类型的变量v原子地增加i,并且返回指向v的指针。
intatomic_add_return(inti,atomic_t*v);
11.该函数从原子类型的变量v中减去i,并且返回指向v的指针。
intatomic_sub_return(inti,atomic_t*v);
12.该函数对原子类型的变量v原子地增加1并且返回指向v的指针。
intatomic_inc_return(atomic_t*v);
13.该函数对原子类型的变量v原子地减1并且返回指向v的指针。
intatomic_dec_return(atomic_t*v);
自旋锁原语要求的包含文件是<
linux/spinlock.h>
.一个实际的锁有类型spinlock_t.象任何其他数据结构,一个自旋锁必须初始化.这个初始化可以在编译时完成,如下:
spinlock_tmy_lock=SPIN_LOCK_UNLOCKED;
或者在运行时使用:
voidspin_lock_init(spinlock_t*lock);
在进入一个临界区前,你的代码必须获得需要的lock,用:
voidspin_lock(spinlock_t*lock);
注意所有的自旋锁等待是,由于它们的特性,不可中断的.一旦调用spin_lock,将自旋直到锁变为可用.
为释放一个已获得的锁,传递它给:
voidspin_unlock(spinlock_t*lock);
4个函数可以加锁一个自旋锁:
voidspin_lock_irqsave(spinlock_t*lock,unsignedlongflags);
voidspin_lock_irq(spinlock_t*lock);
voidspin_lock_bh(spinlock_t*lock)
4个方法释放一个自旋锁
voidspin_unlock_irqrestore(spinlock_t*lock,unsignedlongflags);
voidspin_unlock_irq(spinlock_t*lock);
voidspin_unlock_bh(spinlock_t*lock);
阻塞的自旋锁操作:
intspin_trylock(spinlock_t*lock);
intspin_trylock_bh(spinlock_t*lock);
2种方式被声明和被初始化:
rwlock_tmy_rwlock=RW_LOCK_UNLOCKED;
/*Staticway*/
rwlock_tmy_rwlock;
rwlock_init(&
my_rwlock);
/*Dynamicway*/
为了记录可用资源的数量,需要一个count计数,标记当前可用资源数量。
需要一个count计数和等待进程的链表头即可。
描述信号量的结构体如下。
在linux中,需要一个结构体记录当前的进程信息(task_struct)。
structsemaphore_waiter的list成员是当进程无法获取信号量的时候挂入semaphore的wait_list成员。
task成员就是记录后续被唤醒的进程信息。
一切准备就绪,现在就可以实现信号量的申请函数。
(1).如果信号量标记的资源还有剩余,自然可以成功获取信号量。
只需要递减可用资源计数。
(2).既然无法获取信号量,就需要将当前进程挂入信号量的等待队列链表上。
(3).schedule()主要是触发任务调度的示意函数,主动让出CPU使用权。
在让出之前,需要将当前进程从运行队列上移除。
既然mutex是一种二值信号量,因此就不需要像semaphore那样需要一个count计数。
由于mutex具有“持锁者才能解锁”的特点,所以我们需要一个变量owner记录持锁进程。
释放锁的时候必须是同一个进程才能释放。
当然也需要一个链表头,主要用来便利睡眠等待的进程。
原理和semaphore及其相似,因此在代码上也有体现。
structmutex_waiter的list成员是当进程无法获取互斥量的时候挂入mutex的wait_list链表。
首先实现申请互斥量的函数。
(1).当mutex->
owner的值为0的时候,代表没有任何进程持有锁。
因此可以直接申请成功。
然后,记录当前申请锁进程的task_struct。
(2).既然不能获取互斥量,自然就需要睡眠等待,挂入等待链表。
互斥量的释放代码实现也同样和semaphore有很多相似之处。
(1).mutex具有“持锁者才能解锁”的特点就是在这行代码体现。
(2).如果等待链表没有进程,那么自然只需要将mutex->
owner置0,代表没有锁是释放状态。
(3).mutex->
owner的值改成当前可以持锁进程的task_struct。
(4).从等待进程链表取出第一个进程,并从链表上移除。
然后就是唤醒该进程。
五、程序清单
原子操作函数如下:
atomic_read(atomic_t*v);
自旋锁函数
voidspin_lock(spinlock_t*lock);
voidspin_unlock(spinlock_t*lock);
描述信号量的结构体
structsemaphore{
unsignedintcount;
structlist_headwait_list;
};
结构体记录当前的进程信息
structsemaphore_waiter{
structlist_headlist;
structtask_struct*task;
实现信号量的申请函数
voiddown(structsemaphore*sem)
{
structsemaphore_waiterwaiter;
if(sem->
count>
0){
sem->
count--;
/*1*/
return;
}
waiter.task=current;
/*2*/
list_add_tail(&
waiter.list,&
sem->
wait_list);
schedule();
/*3*/
}
两个类似的结构体分别描述mutex
structmutex_waiter{
structmutex{
longowner;
申请互斥量的函数
voidmutex_take(structmutex*mutex)
structmutex_waiterwaiter;
if(!
mutex->
owner){
mutex->
owner=(long)current;
/*1*/
互斥量的释放代码
intmutex_release(structmutex*mutex)
if(mutex->
owner!
=(long)current)/*1*/
return-1;
if(list_empty(&
wait_list)){
owner=0;
return0;
waiter=list_first_entry(&
wait_list,structmutex_waiter,list);
list_del(&
waiter->
list);
mutex->
owner=(long)waiter->
task;
wake_up_process(waiter->
task);
/*4*/
return0;
六、实验体会
(需要填写)
指导教师评语: