Chinaunix首页 | 论坛 | 博客
  • 博客访问: 498802
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: LINUX

2015-01-10 23:38:10

所谓原子操作,是指不能被cpu和其他cpu所中断的执行指令或指令流


原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。

原子操作的实现

CPU基本的原子操作

LOCK前缀

自动带LOCK的指令


CPU平台本身可以保证的原子操作

-读或者写一个字节

-读或者写一个对齐的16-bit数据

-读或者写一个对齐的32-bit数据

-读或者写一个对齐的64-bit数据(64位CPU)

另外:

在32-bit的数据总线上访问一块cache禁止的16位数据(>=Petiunm)

在一个cache line中访问不对其的 16,32,64位数据(>=P6 pamily)


LOCK前缀

-指令前带LOCK前缀迫使CPU做独占的内存访问

-XCHG自动带有LOCK前缀

LOCK在不同CPU版本的实现

-在较老的CPU上,产生LOCK信号以用来锁总线

-在>=P6 family,锁cache line


代码示例:

cmpxchg(ptr.old, new):比较*ptr和old的值,如果相等则*ptr = new.在任何时候该函数返回ptr的初始值.因此,如果想要知道ptr的值是否被New替换,只需要检查其返回值是否与old相等。


自动带LOCK前缀的指令

-xchg

-事物内存(TSX on intel)

可以自定义一块transaction region,然后可以在区域结束的时候原子提交,如果成功提交,则其他CPU可以看到该区域的所有更改,如果提交失败则撤销该区域的所有更改操作,进而转入到程序提供的abort代码。


两种主要的类型

-atomic_t的数据

-bit操作

-其他指令


定义:


atomic_t的操作

-所有的操作都定义在include/linux/atomic.h中以及include/asm/atomic.h中

-常用的atomic操作:

ATOMIC_INIT(i)

atomic_set(v,i)

automic_read(v)

automic_add(i,v)

atomic_sub(i,v)

atomic_inc(v)

atomic_dec(v)

atomic_inc_add_test(v) /*测试新值是否为0*/

atomic_dec_add_test(v)

atomic_xchg(v,new)

atomic_cmpxchg(v,old,new)

atomic_add_negative(i,v) /*测试新值是否为负*/

atomic_add_unless(v,a,u) /*如果v不为u,则v加上a,返回非0,否则直接返回0*/


bit操作

-原子性的位操作

-常用的原子位操作

set_bit(nr, *addr)

clear_bit(nr, *addr)

test_bit(nr, *addr)

change_bit(nr, *addr)

test_and_set_bit(nr, addr) /*测试旧位是否已经设置*/

test_and_clear_bit(nr, *addr)

test_and_change_bit(nr, *addr)

-另外,非原子的位操作

__set_bit(nr, *addr)

__clear_bit(nr, *addr)

test_bit(nr, *addr)

__change_bit(nr, *addr)

__test_and_set_bit(nr, addr) /*测试旧位是否已经设置*/


其他指令(包含原子)

- xchg()

- cmpxchg()

- cmpxchg_double()


  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/atomic.h>
  4. #include <linux/delay.h>
  5. #include <linux/kthread.h>

  6. MODULE_LICENSE("GPL");
  7. MODULE_AUTHOR("Chen");
  8. MODULE_DESCRIPTION("The module for atomic");

  9. #define MAX_KTHREAD 10

  10. static unsigned long my_bits;

  11. static void show_my_data(void)
  12. {
  13.     int i, bits = sizeof(my_bits) * 8;

  14.     for (i = 0; i < bits; i++) {
  15.         int set = test_bit(i, &my_bits);

  16.         if (set)
  17.             printk("bit %d is set\n", i);
  18.     }
  19. }

  20. static struct task_struct *threads[MAX_KTHREAD];

  21. static int thread_do(void *data)
  22. {
  23.     long i = (long)data;

  24.     printk("thread %ld is running...\n", i);

  25.     set_bit(i, &my_bits);
  26.     set_bit(i + MAX_KTHREAD, &my_bits);

  27.     while(!kthread_should_stop()) {
  28.         msleep(10);
  29.     }

  30.     return 0;
  31. }

  32. static int create_threads(void)
  33. {
  34.     int i;

  35.     for (i = 0; i < MAX_KTHREAD; i++) {
  36.         struct task_struct *thread;

  37.         thread = kthread_run(thread_do, (void *)(long)i, "thread-%d", i);
  38.         if (IS_ERR(thread))
  39.             return -1;

  40.         threads[i] = thread;
  41.     }

  42.     return 0;
  43. }

  44. static void cleanup_threads(void)
  45. {
  46.     int i;

  47.     for(i = 0; i < MAX_KTHREAD; i++)
  48.         if (threads[i])
  49.             kthread_stop(threads[i]);
  50. }

  51. static __init int minit(void)
  52. {
  53.     printk("call %s.\n", __FUNCTION__);

  54.     if (create_threads())
  55.         goto err;

  56.     return 0;

  57. err:
  58.     cleanup_threads();
  59.     return -1;
  60. }

  61. static __exit void mexit(void)
  62. {
  63.     printk("call %s.\n", __FUNCTION__);
  64.     cleanup_threads();
  65.     show_my_data();
  66. }

  67. module_init(minit);
  68. module_exit(mexit);


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