内核并发控制---自旋锁(来自网易)

定义在头文件linux/spinlock.h中;
自旋锁(spin lock)是一种对临界资源进行互斥访问的典型手段;为了获得一个自旋锁,在某CPU上运行的代码需要首先执行一个原子操作,该操作测试并设置某个内存变量,由于该操作是原子操作,所以在该操作完成之前,其它执行单元对该内存变量的访问被禁止;
如果测试结果表明该自旋锁已经空闲,则程序获得这个自旋锁并继续运行;如果测试结果表明该自旋锁仍然被占用,那么,程序将在一个小的循环内重复执行这个"测试并设置"操作,即,进行所谓的"自旋",通俗地讲就是"在原地打转".当该自旋锁的持有者通过重置该变量释放这个自旋锁之后,某个等待的"测试并设置"操作向其它调用者报告该所已经释放;
理解自旋锁最简单的方法就是把它看成一个变量,该变量把一个临界区或者标记为"我当前正在运行,请稍等一会",或者标记为"我当前不在运行,可以被使用";如果A执行单元首先进入临界区,那么,它将获得并持有该自旋锁;当B执行单元试图进入同一个临界区的时候,将获知该自旋锁已经被持有,需要等到A执行单元释放该自旋锁之后才能进入该临界区;
自旋锁使得设备最多只被一个进程打开;
自旋锁的相关操作:
1).定义自旋锁:
spinlock_t spin;
2).初始化自旋锁:
spin_lock_init(lock);
该函数用于动态初始化自旋锁lock
3).获得自旋锁:
spin_lock(lock);
该函数用于获得自旋锁lock,如果能够立即获得自旋锁,它将马上返回,否则,它将自旋在那里,直到该自旋锁被持有者释放为止;
spin_trylock(lock);
该函数尝试获得自旋锁,如果能够立即获得自旋锁,那么它将得到并持有自旋锁并马上返回真,否则立即返回假,实际上不再"在原地打转"了;
4).释放自旋锁
spin_unlock(lock);
该函数用于释放自旋锁lock;它与spin_lock()或spin_trylock()配对使用;
自旋锁的使用套路:
spinlock_t lock;       //定义自旋锁
spin_lock_init(&lock); //初始化自旋锁

spin_lock(&lock);      //获得自旋锁,保护临界区;
......
//临界区代码
......
spin_unlock(&lock);    //释放自旋锁
自旋锁主要是针对SMP和单CPU但内核支持可抢占式调度的系统;对于单CPU和内核不支持可抢占式调度的系统来说,自旋锁就退化为空操作了;在单CPU和内核可抢占的系统中,自旋锁被持有期间,内核的抢占被禁止;由于内核可抢占的单CPU系统的行为实际很类似于SMP系统,因此,在这样的单CPU系统中使用自旋锁仍十分必要;
尽管使用了自旋锁可以保证临界区不会受到其它CPU和本CPU内抢占进程的打扰,但是得到自旋锁的代码路径在执行临界区代码的时候仍然可能会被中断和低半部所影响;为了防止这种影响,就需要用到自旋锁的衍生;spin_lock()和spin_unlock()是自旋锁机制的基础;把自旋锁与中断屏蔽、原子操作等手段联合使用,就可以形成一整套完整的自旋锁机制;
关系如下:
spin_lock_irq() = spin_lock() + local_irq_disable();
spin_unlock_irq() = spin_unlock() + local_irq_enable();
spin_lock_irqsave() = spin_lock() + local_irq_save();
spin_unlock_irqrestore() = spin_unlock() + local_irq_restore();
spin_lock_bh() = spin_lock() + local_bh_disable();
spin_unlock_bh() = spin_unlock() + local_bh_enable();
5).驱动程序工程师应该谨慎使用自旋锁,而且在使用中还要注意以下几个问题
:
A.自旋锁实际上是忙等待;当自旋锁不可用的时候,CPU就一直重复循环执行"测试并设置"该锁,直到可用并获得锁为止;CPU在等待自旋锁的时候不做任何有用的事情,仅仅是忙等待而已;因此,只有在占用锁的时间极短的情况下使用自旋锁才是合理的;当临界区范围很大或者是有共享资源的时候,需要较长时间占用自旋锁,这个时候使用自旋锁会降低系统性能;
B.自旋锁可能导致系统死锁;引发这种问题的一个最常见的情况就是递归地使用一个自旋锁,比如:如果一个已经拥有某个自旋锁的CPU想再次获得这个自旋锁,则该CPU就会陷入死锁状态;此外,如果进程获得自旋锁之后进入阻塞状态,也有可能会导致该进程陷入死锁状态;copy_from_user()、copy_to_user()和kmalloc()等函数都有可能会引起阻塞而导致陷入死锁状态,因此在自旋锁被占用期间不能调用这些函数;
6).其它函数/宏:
spin_is_locked(spinlock):
该宏用于判断自旋锁spinlock是否已经被某执行单元所持有(锁定);如果是,则返回真,否则返回假;
spin_unlock_wait(spinlock):
该宏用于等待自旋锁spinlock变得没有被任何执行单元所持有,也即:等待自旋锁spinlock被所有持有该锁的执行单元释放;如果所有持有自旋锁spinlock的执行单元都已经释放该锁(即:自旋锁spinlock不再被任何执行单元所持有),则该宏立即返回,否则就循环在那里,直到该锁被所有持有该锁的执行单元释放为止;
例子:
#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 <linux/spinlock.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("*************");
MODULE_VERSION("2.6.35.000");

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

//STEP1:定义自旋锁
spinlock_t my_spin_lock;

//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;
    }

    //STEP3:对临界区加锁
    spin_lock(&my_spin_lock);
    shared_res++;
    //STEP4:对临界区解锁
    spin_unlock(&my_spin_lock);

    mdelay(sleep_time);
  }
  return 12;
};

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;
    }

    //STEP3:对临界区加锁
    spin_lock(&my_spin_lock);
    shared_res++;
    //STEP4:对临界区解锁
    spin_unlock(&my_spin_lock);

    msleep(sleep_time);
  }
  return 34;
};

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;
    }

    //STEP3:对临界区加锁
    spin_lock(&my_spin_lock);
    val = shared_res;
    printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
    //STEP4:对临界区解锁
    spin_unlock(&my_spin_lock);

    msleep(sleep_time);
  }
  return 56;
};

static int thread_process4(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;
    }

    //STEP3:对临界区加锁
    spin_lock(&my_spin_lock);
    val = shared_res;
    printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
    //STEP4:对临界区解锁
    spin_unlock(&my_spin_lock);

    msleep(sleep_time);
  }
  return 78;
};

static struct task_struct* my_thread1 = NULL;
static struct task_struct* my_thread2 = NULL;
static struct task_struct* my_thread3 = NULL;
static struct task_struct* my_thread4 = NULL;

static int __init study_init(void)
{
 int err = 0;
 printk("%s\n", __PRETTY_FUNCTION__);

 //STEP2:初始化自旋锁
 spin_lock_init(&my_spin_lock);
 printk("init spin lock ok\n");

 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;
 }

 my_thread4 = kthread_create(thread_process4, NULL, "my_thread4");
 if(IS_ERR(my_thread4))
 {
   err = PTR_ERR(my_thread4);
   my_thread4 = NULL;
   printk(KERN_ERR "unable to start kernel thread4:%d\n", err);
   return err;
 }

 wake_up_process(my_thread1);
 wake_up_process(my_thread2);
 wake_up_process(my_thread3);
 wake_up_process(my_thread4);
 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);
 }

 if(my_thread4)
 {
   ret = kthread_stop(my_thread4);
   my_thread4 = NULL;
   printk("kernel thread4 stop,exit code is %d;\n",ret);
 }

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

module_init(study_init);
module_exit(study_exit);

资源下载链接为: https://pan.quark.cn/s/5c50e6120579 在Android移动应用开发中,定位功能扮演着极为关键的角色,尤其是在提供导航、本地搜索等服务时,它能够帮助应用获取用户的位置信息。以“baiduGPS.rar”为例,这是一个基于百度地图API实现定位功能的示例项目,旨在展示如何在Android应用中集成百度地图的GPS定位服务。以下是对该技术的详细阐述。 百度地图API简介 百度地图API是由百度提供的一系列开放接口,开发者可以利用这些接口将百度地图的功能集成到自己的应用中,涵盖地图展示、定位、路径规划等多个方面。借助它,开发者能够开发出满足不同业务需求的定制化地图应用。 Android定位方式 Android系统支持多种定位方式,包括GPS(全球定位系统)和网络定位(通过Wi-Fi及移动网络)。开发者可以根据应用的具体需求选择合适的定位方法。在本示例中,主要采用GPS实现高精度定位。 权限声明 在Android应用中使用定位功能前,必须在Manifest.xml文件中声明相关权限。例如,添加<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />,以获取用户的精确位置信息。 百度地图SDK初始化 集成百度地图API时,需要在应用启动时初始化地图SDK。通常在Application类或Activity的onCreate()方法中调用BMapManager.init(),并设置回调监听器以处理初始化结果。 MapView的创建 在布局文件中添加MapView组件,它是地图显示的基础。通过设置其属性(如mapType、zoomLevel等),可以控制地图的显示效果。 定位服务的管理 使用百度地图API的LocationClient类来管理定位服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值