|
文件: |
sema.rar |
大小: |
3KB |
下载: |
下载 | |
更多的讨论可以到这里:
/* * Author:bob_zhang2004@163.com * 本例子是个练习互斥同步的例子,你可以自由copy,随意修改 * 如果你要扩充或者修改,而且自己觉得很好,可以发给我到上面的mail */
/* * 练习的小项目: * 实际上是实现了一个类似信号量的一个东西:系统有n个资源(用struct bob_resource来定义),当用户read的时候,先判断资源个数 > 0 * 如果>0,就继续执行,如果<0 就进入等待队列,并用sleepers来记录睡眠的进程个数。 * 当获得资源的进程释放的资源以后, 就必须left_res_nr++ ,然后唤醒等待队列中的进程, 当某个进程被调度后, sleepers就会递减。 */ /* * 学习重点: * 掌握住信号量,自旋锁,原子操作,等待队列的用法,包括如何声明,如何初始化,特别自旋锁和信号量的初始化方法 * 熟练 常用的函数的用法 */
/* 练习中关于互斥和避免静态条件注意的问题: * 为什么我要在里面加上自旋锁的保护,不加可不可以呢? * 里面我加的自旋锁的保护效率是否高呢?临界区会不会太长? * 仔细想想,如果不加自旋锁的保护,大概会出现什么样的静态条件呢? */ /* * 下一步的练习 * 更加深入的学习, 用保护的时机 */
/* 最后看我的总结,在程序的最后面 */
#include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/uaccess.h> /* for put_user()/get_user() */ #include <linux/init.h> #include <linux/compiler.h> #include <linux/list.h> /* struct list_head */ #include <linux/delay.h> /* mdelay() */
#define KERNEL_DEBUG //defined debug function
#include "mod_head.h"
//bob自己的资源结构体,其实有点类似于semaphore的定义
//在这里我们自己练习一下semaphore是怎么样实现的,当然我们都是用c实现的
//实际工作中,可能要用汇编语言提高效率
typedef struct bob_resource { spinlock_t spin_lock; //保护该资源结构的自旋锁,用在SMP处理机上,对于单处理机上,可以防止抢占
char res_name[20]; //资源的名称
atomic_t left_res_nr; //剩余的资源个数
atomic_t sleepers; //因为得不到资源而睡眠的进程个数
wait_queue_head_t res_wait_queue; //睡眠进程所在的等待队列
}resource_t;
resource_t tt_res;
static int pid_n = 0;
static __init int chardev_init(void); static __exit void chardev_exit(void);
static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); static ssize_t device_read(struct file *, char *, size_t, loff_t *); //static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
#define SUCCESS 0 #define DEVICE_NAME "chardev_bob_test" /* Dev name as it appears in /proc/devices */
static int Major;
static int device_open(struct inode *inode, struct file *file) { //MOD_INC_USE_COUNT;
try_module_get(THIS_MODULE);
return SUCCESS; }
static int device_release(struct inode *inode, struct file *file) {
//MOD_DEC_USE_COUNT;
module_put(THIS_MODULE); return 0; } /* void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); __add_wait_queue(q, wait); spin_unlock_irqrestore(&q->lock, flags); } */ //由此可以看出, add_wait_queue() 是安全的,并不会发生静态条件
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ char *buffer, /* buffer to fill with data */ size_t length, /* length of the buffer */ loff_t *offset) /* loff_t == long long */ { int ret = 0; int i=0; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&(tt_res.res_wait_queue), &wait); do { __set_current_state(TASK_INTERRUPTIBLE); dbg("tt_res.left_res_nr.counter = %d\n",tt_res.left_res_nr.counter); spin_lock(&(tt_res.spin_lock)); //防止抢占(UP) ,加锁保护(SMP)
if(atomic_read(&(tt_res.left_res_nr)) > 0) { if(atomic_read(&(tt_res.sleepers)) > 0) atomic_dec(&(tt_res.sleepers)); ret = 0; break; } atomic_inc(&(tt_res.sleepers)); spin_unlock(&(tt_res.spin_lock)); schedule(); } while (1); atomic_dec(&(tt_res.left_res_nr)); set_current_state(TASK_RUNNING); remove_wait_queue(&(tt_res.res_wait_queue), &wait); spin_unlock(&(tt_res.spin_lock)); /* 这里实际上就是你自己要执行的代码 ,我这里仅仅是个例子,睡眠了10秒钟而已 * ============================================================================== */ dbg("I am %dth process \n",++pid_n); //do something
dbg("I begin to do somthing baseon the resource \n"); dbg("in fact ,I will sleep 10s\n"); //sleep 10s
while(i < 100) { mdelay(100); i++; } /*==============================================================================*/ //思考:为什么,我会注释掉这里的自旋锁的保护呢?如果这个时候发生了进程切换又会怎么样呢?
dbg("current ,tt_res.left_res_nr.counter = %d\n",atomic_read(&(tt_res.left_res_nr))); // spin_lock(&(tt_res.spin_lock));
atomic_inc(&(tt_res.left_res_nr)); // spin_unlock(&(tt_res.spin_lock));
dbg("I have free resource \ntt_res.left_res_nr.counter = %d\n",atomic_read(&(tt_res.left_res_nr))); //唤醒等待队列里面的进程
//保护tt_res.sleepers ,因为上面的 atomic_dec(&(tt_res.sleepers)); 在别的进程中也会修改 sleepers 可能会引发静态条件
spin_lock(&(tt_res.spin_lock)); if(atomic_read(&(tt_res.sleepers)) > 0) { dbg("sleepers = %d\n",atomic_read(&(tt_res.sleepers))); wake_up_interruptible(&(tt_res.res_wait_queue)); } spin_unlock(&(tt_res.spin_lock)); return ret; }
static struct file_operations fops = { .owner = THIS_MODULE, .read = device_read, .open = device_open, .release= device_release //others are NULL;
};
static __init int chardev_init(void) { Major = register_chrdev(0, DEVICE_NAME, &fops); if (Major < 0) { dbg("Registering the character device failed with %d\n", Major); return Major; } //resource excerise,resource initializing
//init_MUTEX(&(tt_res.sema_lock)); //互斥信号量
spin_lock_init(&(tt_res.spin_lock)); strcpy(tt_res.res_name,"bob_resource"); //默认的资源个数只有 1 个, 便于调试方便,你可以自己更改更多的,变成类似多元信号量
atomic_set(&(tt_res.left_res_nr),1); atomic_set(&(tt_res.sleepers),0); init_waitqueue_head(&(tt_res.res_wait_queue)); return 0; }
static __exit void chardev_exit(void) { /* * Unregister the device */ int ret = unregister_chrdev(Major, DEVICE_NAME); struct list_head *p = NULL; if (ret < 0) dbg("Error in unregister_chrdev: %d\n", ret); }
module_init(chardev_init); module_exit(chardev_exit);
MODULE_AUTHOR("Bob Zhang bob.zhang2004@gmail.com"); MODULE_DESCRIPTION("Excerise for spinlock,mutex,atomic etc."); MODULE_LICENSE("GPL");
/* 总结: * 1。什么时候要加保护,一个数据结构,在一段代码里面,既有读 ,又有写, 显然要加保护,因为进程是并发的, * 2。可能一个进程正在写, 另外一个进程正在读,为防止静态条件, 要加保护,可以是信号量,也可以是spinlock * 对于结构 if(a) { xxx; } * 要加保护,防止静态 */
|