您的位置:首页 > 其它

内核并发控制---原子操作(来自网易)

2012-10-08 15:43 330 查看
定义在头文件asm/atomic.h中;

原子操作指的是在执行过程中不会被别的代码路径所打断的操作;

Linux内核提供了一系列的函数来实现内核中的原子操作,这些函数又分为两类,分别针对位变量和整型变量进行原子操作;它们的共同点是:在任何情况下操作都是原子的,内核代码可以安全地调用它们而不会被打断;位变量和整型变量的原子操作都依赖于底层CPU的原子操作来实现,因此所有这些函数都是与CPU架构密切相关;

使用原子变量的操作,可以使设备最多只能被一个进程打开;
一、整型原子变量操作
1).设置原子变量的值:

void atomic_set(atomic_t* v, int i); //设置原子变量v的值为i;

atomic_t v = ATOMIC_INIT(0); //定义原子变量v,并初始化为0;

2).获取原子变量的值:

atomic_read(atomic_t* v); //返回原子变量v的值;

3).原子变量加/减:

void atomic_add(int i, atomic_t* v); //原子变量v增加i;

void atomic_sub(int i, atomic_t* v); //原子变量v减少i;

4).原子变量自增/自减:

void atomic_inc(atomic_t* v); //原子变量增加1;

void atomic_dec(atomic_t* v); //原子变量自减1;

5).操作并测试:

int atomic_inc_and_test(atomic_t* v);        //先自增1,然后测试其值是否为0,若为0,则返回true,否则返回false;

int atomic_dec_and_test(atomic_t* v);        //先自减1,然后测试其值是否为0,若为0,则返回true,否则返回false;

int atomic_sub_and_test(int i, atomic_t* v); //先加i,然后测试其值是否为0,若为0,则返回true,否则返回false;

6).操作并返回:

int atomic_add_return(int i, atomic_t* v);   //v的值加i后返回新的值;

int atomic_sub_return(int i, atomic_t* v);   //v的值减i后返回新的值;

int atomic_inc_return(atomic_t* v); //v的值自增1后返回新的值;

int atomic_dec_return(atomic_t* v); //v的值自减1后返回新的值;
二、位原子变量操作

1).设置/清除位:

void set_bit(int nr, volatile void* addr);    //设置地址addr的第nr位,所谓设置位,就是把位写为1;

void clear_bit(int nr, volatile void* addr);  //清除地址addr的第nr位,所谓清除位,就是把位写为0;

2).改变位:

void change_bit(int nr, volatile void* addr); //把地址addr的第nr位反转;

3).测试位:

int test_bit(int nr, volatile void* addr);    //返回地址addr的第nr位;

4).测试并操作位:

int test_and_set_bit(int nr, volatile void* addr);    //测试并设置位;若addr的第nr位非0,则返回true; 若addr的第nr位为0,则返回false;

int test_and_clear_bit(int nr, volatile void* addr);  //测试并清除位;若addr的第nr位非0,则返回true; 若addr的第nr位为0,则返回false;

int test_and_change_bit(int nr, volatile void* addr); //测试并反转位;若addr的第nr位非0,则返回true; 若addr的第nr位为0,则返回false;
注意:位变量的操作函数中的参数nr的取值从0开始计算:[0,7]或[0,15]或[0,31]或[0,63];
例子:

#include <linux/module.h>

#include <linux/version.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/jiffies.h>

#include <linux/delay.h>

//这三个头文件与内核线程的使用有关;

#include <linux/sched.h>

#include <linux/kthread.h>

#include <linux/err.h>

//原子操作相关

#include <asm/atomic.h>

MODULE_LICENSE("GPL");

MODULE_AUTHOR("*************");

MODULE_VERSION("2.6.35.000");

static int sleep_time = (1*10*HZ);

static atomic_t shared_res;

static unsigned int bit_var = 3;

//STEP5:实现线程函数

static int thread_process1(void* param)

{

  int val = 0, ret = 0;

  while(1)

  {

    set_current_state(TASK_UNINTERRUPTIBLE);

    if(kthread_should_stop())

    {

      printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);

      break;

    }

    set_bit(0, (volatile void*)&bit_var);

    printk("%s: set bit_var = %u;\n", __FUNCTION__, bit_var);

    clear_bit(0, (volatile void*)&bit_var);

    printk("%s: clear bit_var = %u;\n", __FUNCTION__, bit_var);

    //atomic_add(1, &shared_res);

    //val = atomic_read(&shared_res);

    //val = atomic_add_return(1, &shared_res);

    //val = atomic_inc_return(&shared_res);

    ret = atomic_inc_and_test(&shared_res);

    val = atomic_read(&shared_res);

    printk("%s: shared resource = %d, true=%d;\n%s", __FUNCTION__, val, ret, ((val % 3) ? "" : "\n"));

    mdelay(sleep_time);

  }

  return 123;

};

static int thread_process2(void* param)

{

  int val = 0, ret = 0;

  while(1)

  {

    set_current_state(TASK_UNINTERRUPTIBLE);

    if(kthread_should_stop())

    {

      printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);

      break;

    }

    set_bit(0, (volatile void*)&bit_var);

    printk("%s: set bit_var = %u;\n", __FUNCTION__, bit_var);

    clear_bit(0, (volatile void*)&bit_var);

    printk("%s: clear bit_var = %u;\n", __FUNCTION__, bit_var);

    //atomic_add(1, &shared_res);

    //val = atomic_read(&shared_res);

    //val = atomic_add_return(1, &shared_res);

    //val = atomic_inc_return(&shared_res);

    ret = atomic_inc_and_test(&shared_res);

    val = atomic_read(&shared_res);

    printk("%s: shared resource = %d, true=%d;\n%s", __FUNCTION__, val, ret, ((val % 3) ? "" : "\n"));

    msleep(sleep_time);

  }

  return 456;

};

static int thread_process3(void* param)

{

  int val = 0, ret = 0;

  while(1)

  {

    set_current_state(TASK_UNINTERRUPTIBLE);

    if(kthread_should_stop())

    {

      printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);

      break;

    }

    set_bit(0, (volatile void*)&bit_var);

    printk("%s: set bit_var = %u;\n", __FUNCTION__, bit_var);

    clear_bit(0, (volatile void*)&bit_var);

    printk("%s: clear bit_var = %u;\n", __FUNCTION__, bit_var);

    //atomic_add(1, &shared_res);

    //val = atomic_read(&shared_res);

    //val = atomic_add_return(1, &shared_res);

    //val = atomic_inc_return(&shared_res);

    ret = atomic_inc_and_test(&shared_res);

    val = atomic_read(&shared_res);

    printk("%s: shared resource = %d, true=%d;\n%s", __FUNCTION__, val, ret, ((val % 3) ? "" : "\n"));

    msleep(sleep_time);

  }

  return 789;

};

static struct task_struct* my_thread1 = NULL;

static struct task_struct* my_thread2 = NULL;

static struct task_struct* my_thread3 = NULL;

static int __init study_init(void)

{

 int err = 0;

 printk("%s\n", __PRETTY_FUNCTION__);

 //shared_res = ATOMIC_INIT(0);

 //printk("int-atomic ATOMIC_INIT=%d\n", atomic_read(&shared_res));

 atomic_set(&shared_res, -100);

 printk("int-atomic atomic_set=%d\n", atomic_read(&shared_res));

 my_thread1 = kthread_create(thread_process1, NULL, "my_thread1");

 if(IS_ERR(my_thread1))

 {

   err = PTR_ERR(my_thread1);

   my_thread1 = NULL;

   printk(KERN_ERR "unable to start kernel thread1:%d\n", err);

   return err;

 }

 my_thread2 = kthread_create(thread_process2, NULL, "my_thread2");

 if(IS_ERR(my_thread2))

 {

   err = PTR_ERR(my_thread2);

   my_thread2 = NULL;

   printk(KERN_ERR "unable to start kernel thread2:%d\n", err);

   return err;

 }

 my_thread3 = kthread_create(thread_process3, NULL, "my_thread3");

 if(IS_ERR(my_thread3))

 {

   err = PTR_ERR(my_thread3);

   my_thread3 = NULL;

   printk(KERN_ERR "unable to start kernel thread3:%d\n", err);

   return err;

 }

 wake_up_process(my_thread1);

 wake_up_process(my_thread2);

 wake_up_process(my_thread3);

 printk("%s:all kernel thread start;\n", __FUNCTION__);

 return 0;

}

static void __exit study_exit(void)

{

 int ret = -1;

 printk("%s\n",__PRETTY_FUNCTION__);

 if(my_thread1)

 {

   ret = kthread_stop(my_thread1);

   my_thread1 = NULL;

   printk("kernel thread1 stop,exit code is %d;\n",ret);

 }

 if(my_thread2)

 {

   ret = kthread_stop(my_thread2);

   my_thread2 = NULL;

   printk("kernel thread2 stop,exit code is %d;\n",ret);

 }

 if(my_thread3)

 {

   ret = kthread_stop(my_thread3);

   my_thread3 = NULL;

   printk("kernel thread3 stop,exit code is %d;\n",ret);

 }

 printk("%s:all kernel thread stop;\n", __FUNCTION__);

}

module_init(study_init);

module_exit(study_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息