我是靠谱客的博主 洁净紫菜,最近开发中收集的这篇文章主要介绍Linux内核并发机制----原子操作,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

并发机制的由来:

       很多人会问这样的问题,Linux内核中提供了各式各样的锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态。这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题。

原子概念: 

       所谓的原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就是说,它的最小的执行单位,不能有比它更小的执行单元,因此这里的原子实际是使用了物理学里物质微粒的概念。

定义:

       Linux提供了一组操作来保证对变量的原子操作。这些操作可用来避免简单的竞争条件。原子操作执行时不会被打断或干扰。在单处理器上,一旦启动原子操作,则从操作开始到结束的这段 时间内,不会中断线程。此外,在多处理器系统中,原子操作所针对的变量被锁定,以免被其他进程访问,直到原子操作结束。

具体实现:

       原子操作主要用来实现资源计数,很多引用计数就是通过原子操作实现的。
typedef struct {int counter;}atomic_t;

该函数对原子类型的变量进行原子读操作,它返回原子类型的变量v的值。
(1)atomic_read(atomic_t *v)

该函数设置原子类型的变量v的值为i。
(2)atomic_set(atomic_t *v,int i);

该函数给原子类型变量v增加i。
(3)atomic_add(int i, atomic_t *v);

该函数给原子类型变量v减去i。
(4)atomic_sub(int i, atomic_t *v);

该函数从原子类型的变量v中减去i,并判断结果是否是0,如果为0,返回真,否则返回假。
(5)atomic_sub_and_test(int i, atomic_t *v);

该函数对原子变量v的增加1。
(6) atomic_inc(atomic_t *v);

该函数对原子变量v原子的减少1。
(7)atomic_dec(atomic_t *v);

该函数先测试后操作,先判断结果是否为0,如果是0,返回真,然后对原子变量v减少1.
(8)atomic_dec_and_test(atomic_t *v);

该函数先测试后操作,先判断结果是否为0,如果是0,返回真,然后对原子变量v增加1.
(9)atomic_inc_and_test(atomic_t *v);

该函数属于先操作后返回,对原子类型的变量v原子的增加i,并且返回指向新的的指针。
(10)atomic_add_return(int i, atomic_t *v);

该函数属于先操作后返回,对原子类型的变量v原子的减少i,并且返回指向新的的指针。
(11)atomic_sub_return(int i, atomic_t *v);

demo:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/compat.h>
#include <linux/chio.h>		
#include <linux/mutex.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/ak4113.h>
#include <sound/asoundef.h>
#include <sound/info.h>
/*
   oop编程的思想:
        1.设计和分配结构体
        2.设置
        3.注册
 */
 //static 它的作用域只在本文件中
#define LKM_NAME "lkm_memory"
#define LKM_MEM_SIZE 1024
//构造对象的结构体
struct lkm_memory_dev{     
       atomic_t open_count;
	unsigned char *lkm_mem_name;
       int lkm_mem_major;
       int lkm_mem_minor;
	struct file_operations *fops;
       struct class *lkm_mem_class;
       unsigned char *memory[LKM_MEM_SIZE];  //内存总空间
	unsigned short len; //current mem len  当前内存长度

};
//建立全局结构体对象
static struct lkm_memory_dev *plkm_memory_dev;

static int lkm_mem_open(struct inode * pinode, struct file * filep)
{ 
        printk("lkm_memory_openn");
	 //如何进行LKM对象的注册,将每个设备的对象注册在属于该设备的文件私有数据域中
	 //为啥重要呢?
	  filep->private_data=plkm_memory_dev;
	 //根据原子变量的值做判断,当前设备是否已经被打开过
	  if(!atomic_dec_and_test(&plkm_memory_dev->open_count))
	  {
              printk("lkm_memory_busy");
	      atomic_inc(&plkm_memory_dev->open_count);
		return -EBUSY;
	  }
	  return 0;

}
//参数四 :位置
static ssize_t lkm_mem_read (struct file *filp, char __user *buf, size_t len, loff_t * pos)
{
	unsigned long ptmp  = *pos;
	unsigned int  count = len;
	int 		  iRet  =0;
	printk("lkm_memory_readn");
	//拿到LKM对象
	struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filp->private_data;
	if(ptmp == 0)
	{
		return 0;
	}
	if(count > ptmp)
		count=ptmp;
	//主要作用就是从内核空间拷贝一块儿数据到用户空间
	if(copy_to_user(buf,dev->memory+ptmp,count))
	{
		iRet = -EFAULT;
	}
	else
	{
		 *pos -= count;
		 iRet = count;
		 printk("lkm_memory:read %u bytes from %lun",count,ptmp);
	}
	return iRet;
    
}
static ssize_t lkm_mem_write (struct file *filp, const char __user * buf, size_t len, loff_t * pos)
{
	//读写指针自己动
    unsigned long ptmp  = *pos;
	unsigned int  count = len;
	int 		  iRet  =0;
	printk("lkm_memory_writen");
	//拿到LKM对象
	struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filp->private_data;
	
	if(ptmp >=LKM_MEM_SIZE)
	{
		return 0;
	}
	if(count >LKM_MEM_SIZE-ptmp)
		count=LKM_MEM_SIZE-ptmp;
	if(copy_from_user(dev->memory+ptmp,buf,count))
	{
		iRet = -EFAULT;
	}
	else
	{
		 *pos += count;
		 iRet = count;
		 printk("lkm_memory:written %u bytes from %lun",count,ptmp);
	}
	return iRet;
}
static int lkm_mem_release(struct inode *pinode, struct file *filep)
{
       printk("lkm_memory_releasen");
	 //拿到设备结构体
       struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filep->private_data;
	filep->private_data = NULL;
	atomic_inc(&plkm_memory_dev->open_count);
	    return 0;
 
}
//分配
static struct file_operations lkm_mem_fops={
      .owner=THIS_MODULE,           //指定当前模块
      .open=lkm_mem_open,
      .release=lkm_mem_release,
      .read=lkm_mem_read,
      .write=lkm_mem_write,
};


static int lkm_memory_setup_dev(struct lkm_memory_dev * dev,int index)
{
       dev->lkm_mem_minor=index;
	memset(dev->memory,0,LKM_MEM_SIZE);
	dev->len=0;
	//创建lkm时,初始化当前打开计数为1
	atomic_inc(&dev->open_count);
	return 1;
}
static __init int lkm_init(void)
{
    int iRet;
	printk("SQ:module loadedn");
	//为当前LKM对象分配内存                                内存类型
	//除了申请内核内存外,还会对申请到的内存内容清零。
	plkm_memory_dev=kzalloc(sizeof(struct lkm_memory_dev), GFP_KERNEL);

	if(!plkm_memory_dev)
	{
        iRet=-ENOMEM;
	    printk(KERN_ERR"lkm_memory:can't malloc memoryn"); 
	    goto error_alloc;
	}
      //对LKM进行设置
      //对lkm_mem_name 分配一个内存
    plkm_memory_dev->lkm_mem_name=kzalloc(sizeof(LKM_NAME), GFP_KERNEL);
	if( !plkm_memory_dev->lkm_mem_name)
	{
        iRet=-ENOMEM;
	    printk(KERN_ERR"lkm_mem_name:can't malloc memoryn"); 
	    goto error_alloc_name;
	}
      //对name 赋值
      memcpy(plkm_memory_dev->lkm_mem_name,LKM_NAME,sizeof(LKM_NAME));
      plkm_memory_dev->fops=&lkm_mem_fops;
      plkm_memory_dev->lkm_mem_major= register_chrdev(0,  plkm_memory_dev->lkm_mem_name,plkm_memory_dev->fops);
      if (plkm_memory_dev->lkm_mem_major< 0) 
	  {
	  	iRet=plkm_memory_dev->lkm_mem_major;
		printk(KERN_ERR"lkm_memory:can't register char devicen"); 
		goto error_register;
	   }
       //调用当前的LKM结构体综合设置函数
       iRet=lkm_memory_setup_dev(plkm_memory_dev,0);  
       if(!iRet)
       {
         iRet=-EINVAL;
         printk(KERN_ERR"lkm_memory:lkm_memory_setup_dev_errorn");  
         goto error_set_dev;
        }
	   
     plkm_memory_dev->lkm_mem_class = class_create(THIS_MODULE, plkm_memory_dev->lkm_mem_name);
	 if (IS_ERR(plkm_memory_dev->lkm_mem_class)) 
	 {
	      iRet=PTR_ERR(plkm_memory_dev->lkm_mem_class);
		printk(KERN_ERR"lkm_memory:can't class_createn");  
		goto error_class_create;
	}
      //devt相当于num 
      //主从设备号的合体
 
       //主设备号对应一个类
       //从设备号对应一个相应的设备
      device_create(plkm_memory_dev->lkm_mem_class, NULL,MKDEV(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_minor), 
      NULL,plkm_memory_dev->lkm_mem_name);

	return 0;
  
error_class_create:
error_set_dev:
	   unregister_chrdev(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_name);
error_register:
       kfree(plkm_memory_dev->lkm_mem_name);	
error_alloc_name:
	   kfree(plkm_memory_dev);
error_alloc:
	return iRet;
	
	
}

static __exit void lkm_exit(void)
{
	printk("SQ:module removedn");
	device_destroy(plkm_memory_dev->lkm_mem_class, MKDEV(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_minor));
	class_destroy(plkm_memory_dev->lkm_mem_class);
	unregister_chrdev(plkm_memory_dev->lkm_mem_major, plkm_memory_dev->lkm_mem_name);
	kfree(plkm_memory_dev->lkm_mem_name);	
	kfree(plkm_memory_dev);
}


module_init(lkm_init);
module_exit(lkm_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("SQ");
MODULE_DESCRIPTION("LKM  OOP");
MODULE_VERSION("1.0");

测试:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define LKM_MEM_SIZE  1024

int main(int argc , char *argv[])
{
	 int fd;
	 unsigned int len=0;
	 unsigned char buf[LKM_MEM_SIZE];
	 fd =open("/dev/lkm_memory",O_RDWR);
	 if(fd<0)
	 {
		 printf("can't openn");
	 }
	 while(1)
	 {
		 len=write(fd,"hello world",sizeof("hello world"));
		 read(fd,buf,len);
		 printf("LKM-READ :%sn",buf);
		 sleep(10);
	 }
	return 0;
}

结果:

           

 

最后

以上就是洁净紫菜为你收集整理的Linux内核并发机制----原子操作的全部内容,希望文章能够帮你解决Linux内核并发机制----原子操作所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部