Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1638784
  • 博文数量: 197
  • 博客积分: 10046
  • 博客等级: 上将
  • 技术积分: 1983
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-07 12:36
个人简介

在外企做服务器开发, 目前是项目经理, 管理两个server开发的项目。不做嵌入式好久了。

文章分类
文章存档

2011年(2)

2010年(6)

2009年(18)

2008年(30)

2007年(100)

2006年(41)

分类: LINUX

2007-10-04 16:00:45

文件: 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;
      }
 * 要加保护,防止静态
 */

阅读(2864) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~