一 原子操作

指令以原子的方式执行——执行过程不被打断。

1 原子整数操作

原子操作函数接收的操作数类型——atomic_t

//定义
atomic_t v;
//初始化
atomic_t u = ATOMIC_INIT(0); //操作
atomic_set(&v,4); // v = 4
atomic_add(2,&v); // v = v + 2 = 6
atomic_inc(&v); // v = v + 1 = 7
//实现原子操作函数实现
static inline void atomic_add(int i, atomic_t *v)
{
unsigned long tmp;
int result;
__asm__ __volatile__("@ atomic_add\n"
    "1: ldrex %0, [%3]\n"
    " add %0, %0, %4\n"
    " strex %1, %0, [%3]\n"
    " teq %1, #0\n"
    " bne 1b"
  : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
  : "r" (&v->counter), "Ir" (i)
  : "cc");
}

 

2 原子位操作

//定义
unsigned long word = 0; //操作
set_bit(0,&word); //第0位被设置1
set_bit(0,&word); //第1位被设置1
clear_bit(1,&word); //第1位被清空0 //原子位操作函数实现
static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)
{
unsigned long flags;
unsigned long mask = 1UL << (bit & 31); p += bit >> 5;
raw_local_irq_save(flags);
*p |= mask;
raw_local_irq_restore(flags);
}

二 自旋锁

  原子位和原子整数仅能对简单的整形变量进行原子操作,对于复杂的数据复杂的操作并不适用。

需要更复杂的同步方法实现保护机制——锁。

  自旋锁:同一时刻只能被一个可执行线程持有,获得自旋锁时,如果已被别的线程持有则该线程进行循环等待锁重新可用,

然后继续向下执行。

过程如下:

      

    

 

使用锁得基本形式如下:

spinlock_t lock;
//获取锁
spin_lock(&lock);
//临界区
…… //释放锁
spin_unlock(&lock);

使用自旋锁防止死锁:

自旋锁不可递归,自旋处于等待中造成死锁;

中断处理程序中,获取自旋锁前要先禁止本地中断,中断会打断正持有自旋锁的任务,中断处理程序有可能争用已经被持有的自旋锁,造成死锁。

读写自旋锁:将锁的用途直接分为读取和写入。

三 信号量

  信号量:睡眠锁。如果有一个任务试图获取信号量时,

信号量未被占用:该任务获得成功信号量;

信号量已被占用:信号量将任任务推进等待队列,让其睡眠,处理器继续工作;当信号量被释放后,

        唤醒信号量队列中的任务,并获取该信号量。

可有读写信号量。

      

声明信号量:

信号量数据结构:
/* Please don't access any members of this structure directly */
struct semaphore { raw_spinlock_t lock; unsigned int count; struct list_head wait_list; };

静态声明信号量:

//声明可用数量为1信号量
#define DEFINE_SEMAPHORE(name) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) //声明可用数量为n的信号量
#define __SEMAPHORE_INITIALIZER(name, n) \
{ \
.lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock), \ .count = n, \ .wait_list = LIST_HEAD_INIT((name).wait_list), \
}

动态声明信号量:

static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0); }

使用信号量:

  //初始化定义信号量
struct semaphore driver_lock;
sema_init(&driver_lock, 1); //获取信号量
if (down_interruptible(&driver_lock))
return -EINTR;
//执行临界区
…… //释放信号量
up(&driver_lock);

自旋锁与信号量对比:

需求                             使用锁

低开销加锁         :               优先使用自旋锁

短期锁定            :               优先使用自旋锁

长期锁定            :               优先使用信号量

中断上下文加锁   :               使用自旋锁

持有锁需要睡眠   :               使用信号量

四 完成变量

  完成变量:如果在内核中一个任务需要发出信号通知另一个任务发生了某个特定事件,

       使用完成变量去唤醒在等待的任务,使两个任务得以同步。信号量的简易方法。

数据结构:

struct completion {
unsigned int done;
wait_queue_head_t wait;
};

完成变量声明:

动态:#define COMPLETION_INITIALIZER(work) \
{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) } 静态: static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}

完成变量使用:

//等待制定的完成变量
void __sched wait_for_completion(struct completion *x) //发信号唤醒等待的任务
void complete(struct completion *x)

还有实现同步机制诸如:禁止抢占,Seq锁(读写共享数据),顺序和屏障……

(笔记)Linux内核学习(七)之内核同步机制和实现方式的更多相关文章

  1. (笔记)Linux内核学习(一)之内核介绍

    内核与操作系统: 内核是操作系统的核心部分,包含了系统运行的核心过程,决定系统的性能,操作系统启动内核被装入到RAM中: 操作系统与底层硬件设备交互和为运行应用程序提供执行环境. Linux内核与微内 ...

  2. (笔记)Linux内核学习(九)之内核内存管理方式

    一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...

  3. ucore操作系统学习(七) ucore lab7同步互斥

    1. ucore lab7介绍 ucore在前面的实验中实现了进程/线程机制,并在lab6中实现了抢占式的线程调度机制.基于中断的抢占式线程调度机制使得线程在执行的过程中随时可能被操作系统打断,被阻塞 ...

  4. Linux驱动技术(七) _内核定时器与延迟工作

    内核定时器 软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行.实际上,时钟中断处理程 ...

  5. Linux系统学习 七、网络基础—常用网络命令

    1.ifconfig                 #查看网络(设置IP临时生效) 2.hostname [主机名]            #查看或设置主机名       默认的是localhost ...

  6. [笔记]linux命令学习

    scp /root/Downloads/cymothoa-1-beta.tar.gz root@192.168.1.66:/root/ rc.local exit 0前加入: sh /root/abc ...

  7. 浅谈linux读写同步机制RCU

    RCU是linux系统的一种读写同步机制,说到底他也是一种内核同步的手段,本问就RCU概率和实现机制,给出笔者的理解. [RCU概率] 我们先看下内核文档中对RCU的定义: RCU is a sync ...

  8. windows核心编程 - 线程同步机制

    线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...

  9. Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序

    Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...

随机推荐

  1. EasyCriteria 3.0 发布

    EasyCriteria 3.0 发布了,这是一个全新的版本,进行了大量的重构.官方发行说明请看:http://uaihebert.com/?p=1898 EasyCriteria 是一个轻量级的框架 ...

  2. Android 控件架构

    如果说Android上的app是一个有血有肉的人的话,那么人靠衣装马靠鞍,那么控件就是把app装扮的漂漂亮亮的“衣服”.那么安卓的控件到底是如何架构,又是如何渲染的了. 无论是什么控件,在Androi ...

  3. Free download

    http://blogs.msdn.com/b/mssmallbiz/archive/2014/07/07/largest-collection-of-free-microsoft-ebooks-ev ...

  4. Linux:Vim

    模式介绍: Vim具备6种基本模式和5中派生模式. 普通模式 启动后的默认模式,用于:移动光标.删除文本等待,常用命令: dd:删除当前行. [number]dd:连续执行number对应次数的dd命 ...

  5. PAAS平台构建7×24小时高可用应用的方案设计

    本博客迁移到部署在jae上的独立博客系统wordpress,博客地址:点击打开独立博客.欢迎大家一起来讨论IT技术. 现在很多企业都在搭建自己的私有PAAS平台,当然也有很多大型互联网公司搭建共有PA ...

  6. atitit.提升开发效率---MDA 软件开发方式的革命(3)----自动化建表

    atitit.提升开发效率---MDA 软件开发方式的革命(3)----自动化建表 1. 建模在后自动建表 1 1. 传统上,需要首先建表,在业务编码.. 1 2. 模型驱动建表---更多简化法是在建 ...

  7. Hello.class所在路径下, 输入命令:java Hello.class,会出现什么结果,为什么?

    所在路径下, 输入命令:java Hello.class: 因为DOS没有规定路径,所有么有在默认路径下找到Hello.class文件,导致提示 错误: 找不到或无法加载主类 Hello.class.

  8. mac系统安装php redis扩展

    安装步骤如下: 1.下载redis扩展 下载地址:https://nodeload.github.com/nicolasff/phpredis/zip/master 2.下载下来是zip包 手动解压 ...

  9. 数据采集:完美下载淘宝Ip数据库 简单的程序节省60元人民币而不必购买数据库

    曾经做网站类型的程序时,经常需要收集客户端的访问数据,然后加以分析.这需要一个Ip数据库,数据表中显示Ip所在的省份市区等信息.网络上有流传的Ip纯真数据库,一些公开的Web服务也可以查询Ip地址信息 ...

  10. Win7下VS2010使用“ASP.Net 3.5 Claims-aware Template”创建ClaimsAwareWebSite报"HRESULT: 0x80041FEB"错误的解决办法

    问题描述: 使用VS2010的WIF开发模板创建“Claims-aware ASP.NET Site”.“Claims-aware WCF Service”,下载安装后,创建网站时,报错"H ...