概述
并发机制的由来:
很多人会问这样的问题,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内核并发机制----原子操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复