不可睡眠锁:RCU read-copy-updat
来源:互联网 发布:java数组二分查找 编辑:程序博客网 时间:2024/05/17 04:52
RCU(Read-Copy Update),顾名思义就是读-拷贝修改,它是基于其原理命名的。对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然后对副本进行修改,最后使用一个回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的操作。
在定义需要使用rcu的资源时,定义中可以加上__rcu修饰,如:
好处:1、告诉读者这个变量是由rcu所保护的。
2、linux kernel有一个静态的检查工具,他会去检查用rcu申明的指针,是不是用rcu_read_lock()保护的。
然后是call_rcu,原型如下:
call_rcu可以这样使用:
第一次写,失败了。又写了一遍
为什么pmy_data->count1和pmy_data->count2能输出,而用my_data.count1和my_data.count2就显示是0?
因为指针变了。。。
http://www.ibm.com/developerworks/cn/linux/l-rcu/
在定义需要使用rcu的资源时,定义中可以加上__rcu修饰,如:
- static struct our_data __rcu *pmy_data = &my_data;
2、linux kernel有一个静态的检查工具,他会去检查用rcu申明的指针,是不是用rcu_read_lock()保护的。
读者
使用rcu_read_lock()来进入读侧
使用rcu_dereference()来获取指针对应的资源
使用rcu_read_unlock()来退出读侧
可以这样用比如
- struct our_data *data;
- rcu_read_lock();
- data = rcu_dereference(pmy_data);//pmy_data是我们需要读取的指针,返回到data中获取
- printk("read count1 %d count2 %d .\n", data->count1, data->count2);
- rcu_read_unlock();
写者
如果有多个写端,需要写端自己做同步
使用rcu_assign_pointer()来更新指针
使用call_rcu()/synchronize_rcu()来释放旧指针对应的资源
使用call_rcu()和synchronize_rcu()的区别
call_rcu()用来将释放的工作交给后台,可以快速返回,不会导致睡眠
synchronisze_rcu()会等待所有的读者退出再返回,会导致睡眠
- data = kmalloc(sizeof(*data), GFP_KERNEL);//先分配一块内存空间
- if (!data)
- return;
- /*memcpy
函数原型:extern void *memmove(void *dest, const void *src, unsigned int count)
参数说明:dest为目的字符串,src为源字符串,count为要拷贝的字节数。*/ - memcpy(data, pmy_data, sizeof(struct our_data));//然后把需要改写的内容复制到data中
- data->count1 ++;
- data->count2 += 10;
- rcu_assign_pointer(pmy_data, data);//改写内容后通过rcu_assign_pointer将指针更新
- if (tmp != &my_data) {
- synchronize_rcu();//会等待所有的读者退出再返回,会导致睡眠
- kfree(tmp);
- }
- extern void call_rcu(struct rcu_head *head,
- void (*func)(struct rcu_head *head));
- struct our_data {
- int count1;
- int count2;
- struct rcu_head rhead;//先设定一个rcu_hread
- };
- static void rcu_free(struct rcu_head *head)
- {
- struct our_data *data;
- data = container_of(head, struct our_data, rhead);//从结构体中的指针,获取结构体的指针
- kfree(data);//用来释放data
- }
- ...
- call_rcu(&tmp->rhead, rcu_free);//传入rcu_hread指针,定义函数名字
- ...
第一次写,失败了。又写了一遍
- #include
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/err.h>
- #include <linux/slab.h>
- #include <linux/rcupdate.h>
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("chen");
- MODULE_DESCRIPTION("exam for opensource.");
- #define MAX_KTHREADS 10
- struct our_data {
- int count1;
- int count2;
- struct rcu_head rhead;
- };
- static unsigned long reader_bitmap;
- static struct task_struct *kthreads[MAX_KTHREADS];
- static struct our_data my_data;
- static struct our_data __rcu *pmy_data = &my_data;
- static void show_my_data(void)
- {
- printk("my_data.count1 is %d, count2 is %d.\n", my_data.count1, my_data.count2);
- printk("pmy_data.count1 is %d, count2 is %d.\n", pmy_data->count1, pmy_data->count2);
-
- }
- static void set_reader_number(int reader)
- {
- WARN_ON((MAX_KTHREADS - reader) != 1);
- reader_bitmap = 0;
- while(reader)
- {
- reader_bitmap |= 1 << --reader;
- }
- }
- static void reader_do(void)
- {
- struct our_data *data;
- rcu_read_lock();
- data = rcu_dereference(pmy_data);
- printk("read count1 %d count2 %d\n", data->count1, data->count2);
- rcu_read_unlock();
- }
- static void rcu_free(struct rcu_head *head)
- {
- struct our_data *data;
-
- data = container_of(head, struct our_data, rhead);
- kfree(data);
- }
- static void writer_do(void)
- {
- struct our_data *data, *tmp;
- tmp = pmy_data;
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- return;
- memcpy(data, pmy_data, sizeof(struct our_data));
- data->count1 ++;
- data->count2 += 10;
- rcu_assign_pointer(pmy_data, data);
- if (tmp != &my_data)
- call_rcu(&tmp->rhead, rcu_free);
- }
- static void kthread_cleanup(void)
- {
- int i = 0;
- for(i = 0; i < MAX_KTHREADS; i++)
- if (kthreads[i])
- kthread_stop(kthreads[i]);
- }
- static int kthread_do(void *data)
- {
- long i = (long)data;
- int reader = (reader_bitmap & (1 << i));
- printk("run...%ld %s ...\n", i, reader ? "reader" : "writer");
- while(!kthread_should_stop()) {
- if (reader_bitmap & (1 << i))
- reader_do();
- else
- writer_do();
- msleep(10);
- }
-
- return 0;
- }
- static int create_kthread(void)
- {
- int i = 0, ret = 0;
- for(i = 0; i < MAX_KTHREADS; i++) {
- struct task_struct *tsk;
- tsk = kthread_run(kthread_do, (void *)(long)i, "kthread-%d", i);
- if (IS_ERR(tsk)) {
- printk("create kthread err.\n");
- ret = PTR_ERR(tsk);
- goto err;
- }
- kthreads[i] = tsk;
- }
- return ret;
- err:
- kthread_cleanup();
- return ret;
- }
- static int __init main_init(void)
- {
- printk("call %s.\n", __FUNCTION__);
- set_reader_number(9);
- if (create_kthread())
- goto err;
- return 0;
- err:
- kthread_cleanup();
- return -1;
- }
- static void __exit main_exit(void)
- {
- kthread_cleanup();
- show_my_data();
- printk("call %s .\n", __FUNCTION__);
- }
- module_init(main_init);
- module_exit(main_exit);
为什么pmy_data->count1和pmy_data->count2能输出,而用my_data.count1和my_data.count2就显示是0?
因为指针变了。。。
http://www.ibm.com/developerworks/cn/linux/l-rcu/
0
上一篇:不可睡眠锁:自旋锁spinlock编码学习
下一篇:可睡眠锁 互斥量、信号量、读写信号量、完成变量
相关热门文章
- linux 常见服务端口
- xmanager 2.0 for linux配置
- 【ROOTFS搭建】busybox的httpd...
- openwrt中luci学习笔记
- 什么是shell
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 不可睡眠锁:RCU read-copy-updat
- RCU(Read-Copy Update)
- RCU(Read-Copy Update)
- linux内核锁机制-不可睡眠锁之RCU
- 无锁编程(五) - RCU(Read-Copy-Update)
- RCU (Read-Copy Update) 的实现机制
- Linux内核RCU(Read Copy Update)锁简析
- Linux内核RCU(Read Copy Update)锁简析-前传
- RCU(Read-Copy Update)synchronize原理分析
- RCU锁
- RCU 锁
- 不可睡眠锁:自旋锁spinlock编码学习
- Read-copy-update
- read copy update
- rcu锁机制
- linux RCU锁机制。
- RCU锁机制
- linux RCU锁机制
- 内核模块下载和编译、安装
- 3.18内核的sk_buff
- 不可睡眠锁:自旋锁spinlock编码学习
- 8.可变对象(无序表和有序表——含java库中应用)
- LoRa笔记02 LoRa sx1276 sx1278的发射功率研究
- 不可睡眠锁:RCU read-copy-updat
- 可睡眠锁 互斥量、信号量、读写信号量、完成变量
- c++中使用Ctags
- 原子操作
- (一)洞悉linux下的Netfilter&iptables:什么是Netfilter?
- opencv2—(6)基于类的图像处理程序设计
- 简单字符驱动程序mycdev_globalmem.c
- C#多线程学习(一)
- intrins.h头文件
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
大连宜家营业时间
深圳宜家营业时间
成都宜家家居地址
成都宜家家居
宜家会员注册
深圳宜家地址
武汉宜家家居
天津宜家营业时间
宜家家居图片
杭州宜家家居
宜家关门时间
上海宜家营业时间
宜家家居成都
重庆宜家地址
石家庄宜家家居
佛山宜家家居地址
宜家家居app下载
上海宜家家居地址
宜家可以网购吗
成都宜家营业时间
北京宜家家居地址
武汉宜家家居地址
宜家家具质量怎么样
深圳宜家在哪里
宜家退货流程
济南宜家家居
西安宜家家居地址
宜家家居网址
深圳宜家家居
深圳宜家家居地址
宜家家居网上商城家具
宜家有网上商城吗
宜家家居怎么样
佛山宜家家居
北京宜家攻略
武汉宜家地址
无锡宜家地址
西安宜家营业时间
宜家送货上门吗
宜家的家具怎么样
合肥宜家在哪