kk-并发控制和处理

  1. 什么是并发,竞态
  2. 竞态的解决方式
  3. 实际中如何灵活应用

 

## 什么是并发,竞态

  1. 并发(concurrency): 并发是指多个执行单元同时,并行的执行
  2. 竞态(race conditions): 并发的执行单元对共享资源(硬件资源(比如只有一个i2c,一个uart),全局变量等)的访问容易发生数据混乱
  3. 竞态发生的情况

    1 对称多处理器(SMP)的多个CPU,smp是一种紧耦合,共享存储的系统模型,它的特点是多个CPU使用共同给的系统总线,因此可以访问共同的外设和存储器。(多个CPU可以粗略理解为多个线程)

    2 CPU内进程与抢占它的进程--2.6的内核支持抢占调度,一个进程在内核执行的时候可能被另一高优先级进程打断

    3中断(硬中断,软中断, tasklet,底半部)与进程之间:中断可以打断正在执行的进程,处理中断的程序和被打断的进程间也可能发生竞态,此外中断也可以被新的更高优先级的中断打断,因此,多个中断之间本身也可能引起并发而导致竞态。

## 竞态的解决方法

    解决竞态问题的途径是保证对共享资源的互斥访问,访问共享资源的代码区称为临界区,临界区要互斥机制保护,linux设备驱动中常见的互斥机制有以下方式:中断屏蔽,原子操作,自旋锁,信号量

## 实际中如何灵活应用

1 中断屏蔽

1 基本概念:在单CPU中避免竞态的一种简单方法是在进入临界区之前屏蔽系统的中断,由于linux的异步I/O,进程调度等很多内容都依靠中断,所以我们应该尽快的执行完临界区的代码,换句话就是临界区代码应该尽量少


#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#define GLOBALMEM_SIZE  0x1000  			/* 全局内存大小:4KB */
#define MEM_CLEAR       0x01    			/* clear mem */
#define GLOBALMEM_MAJOR 254    				 /* 预设的globalmem的主设备号*/

static dev_t globalmem_major  = GLOBALMEM_MAJOR;

static struct globalmem_dev  {
	struct cdev cdev;				/* cdev 结构体 */
	unsigned char mem[GLOBALMEM_SIZE];  		/* 全局内存 */
};

struct globalmem_dev *globalmem_devp; 			/* 设备结构体指针  */

// open
static int globalmem_open(struct inode *inode,struct file *flip)
{
	/* 将设备结构体指针赋值给文件私有数据指针 */
	flip->private_data = globalmem_devp;
	return 0;
}

// release
static int globalmem_release(struct inode *inode, struct file *flip)
{
	return 0;
}

// ioctl
static long globalmem_ioctl(struct file *flip,unsigned int cmd,unsigned long arg)			
{
	struct globalmem_dev *dev = flip->private_data; /* 获得设备结构体指针 */
	switch (cmd) {
	case MEM_CLEAR:
		memset(dev->mem,0,GLOBALMEM_SIZE);
		printk(KERN_INFO"globalmem is set to zero\n");
		break;
	default:
		return -EINVAL;
		break;

	}
	return 0;
}

// read
static int globalmem_read(struct file *flip, char __user *buf,size_t size,loff_t *ppos)
{
	unsigned long p = *ppos;
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev *dev = flip->private_data; /* 获得设备结构体指针 */
	printk("--%s--\n",__FUNCTION__);
	/*  */
	if (p > GLOBALMEM_SIZE)
		return count ? -ENXIO:0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE-p;

	/* 内核空间-> 用户空间 */
	if (copy_to_user(buf,(void *)(dev->mem + p),count)) {
		ret = -EFAULT;
	}
	else {
		*ppos += count;
		ret = count;
		printk(KERN_INFO "read %d bytes(s)from %ld\n",count,p);
	}
	return ret;

}

// write 
static ssize_t globalmem_write(struct file *flip,const char __user *buf,size_t size,loff_t *ppos)
{
	unsigned long p = *ppos;
	unsigned int count = size;
	int ret = 0;
	struct globalmem_dev *dev = flip->private_data;
	/* 分析和获取有效的写长度 */
	if (p >= GLOBALMEM_SIZE) 
		return count ? -ENXIO:0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE - p;
	/* 内核空间-> 用户空间 */
	if (copy_from_user(dev->mem + p,buf,count))
		ret = -EFAULT;
	else {
		*ppos += count;
		ret = count;
		printk(KERN_INFO"write %d bytes from %ld\n",count,p);
	}
	return ret;
}

static const struct file_operations globalmem_fops = {

	.owner  = THIS_MODULE,
	//.llseek = globalmem_llseek,
	.read   	= globalmem_read,
	.write  	= globalmem_write,
	.unlocked_ioctl = globalmem_ioctl,
	.open   	= globalmem_open,
	.release	= globalmem_release,
};

/* 初始化cdev对象和其行为 并注册 
 * cdev_init
 * cdev_add
 */
static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)
{
	int err,devno = MKDEV(globalmem_major,index);
	cdev_init(&dev->cdev,&globalmem_fops);		/* cdev对象 + 行为*/
	dev->cdev.owner = THIS_MODULE;
	dev->cdev.ops   = &globalmem_fops;		

	err = cdev_add(&dev->cdev,devno,1);		/* cdev对象 + devno */
	if (err) {
		printk(KERN_NOTICE "Error %d adding LED%d",err,index);
	}
	printk("setup_cdev success%d\n",err);	
}



static int __init globalmem_init(void)
{
	int result;
	dev_t devno = MKDEV(globalmem_major,0);

	/* 1 申请设备号 */
#if 0
	if (globalmem_major > 0)
		result = register_chrdev_region(devno,1,"globalmem"); /* 静态分配房间 */
		
	else {
		result = alloc_chrdev_region(&devno,0,1,"globalmem"); /* 动态分配设备号 */
		globalmem_major = MAJOR(devno);			      /* 动态申请后,分配设备号 */
	}
#else
		result = alloc_chrdev_region(&devno,0,1,"globalmem"); /* 动态分配设备号 */
		globalmem_major = MAJOR(devno); 		      /* 动态申请后,分配设备号 */

#endif
	if (result < 0){
		printk("result = %d\n",result);	
		return result;
	}
	printk("globalMajor= %d,result=%d\n",globalmem_major,result);
	
	/* 2 动态申请设备结构体的内存 */
	globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);
	if (!globalmem_devp){ /* 申请失败 */
		result = -ENOMEM;
		goto fail_malloc;
	}
	memset(globalmem_devp,0,sizeof(struct globalmem_dev));

	/* 3 字符设备申请 */
	globalmem_setup_cdev(globalmem_devp,0);
	return 0;

	
	
fail_malloc:
	unregister_chrdev_region(devno,1);
	return result;
	
		
}

static void __exit globalmem_exit(void)
{
	cdev_del(&globalmem_devp->cdev);			/* 注销字符设备 */
	kfree(globalmem_devp);		/* 内存清空 */
	unregister_chrdev_region(MKDEV(globalmem_major,0),1); /* 房间号收回,释放设备号 */

}

MODULE_AUTHOR("xiao wei");
MODULE_LICENSE("GPL");

module_param(globalmem_major,int,S_IRUGO); /* S_IRUGO ? */
module_init(globalmem_init);
module_exit(globalmem_exit);

	



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值