一 原子操作

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

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. vim安装YouCompleteMe 插件

    要安装YouCompleteMe ,vim须支持python.看是否支持,可以在vim中:version 查看, 如果python前有+号,就是支持,减号就是不支持. 如果不支持,需要以编译安装方式重 ...

  2. Mac下修改环境变量

    Mac下修改环境变量 如果使用默认Bash, 首先修改 ~/.bash_profile 文件,添加文件路径,比如: export PATH=~/bin:/usr/local/bin/node:~/Do ...

  3. [ucgui] 对话框3——GUIBuilder生成界面c文件及修改

    >_<" 其实生成GUI有相应的工具:

  4. Scala 中 构造函数,重载函数的执行顺序

    在调试scala在线开发教程(http://www.imobilebbs.com/wordpress/archives/4911)的过程中看到了以下代码,但是这段代码无论怎么调试都无法成功. abst ...

  5. Java-JDK配环境,eclipse工具认识

    一.JDK配环境: 1.JDK思维导图 2.测试代码: 需要注意点位类名大小写的区分,符号为英式输入法下的, ; . class Hello{ public static void main(Stri ...

  6. paip.windows io监控总结

    paip.windows io监控总结 io的主要参数是个.disk queue length 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专 ...

  7. 从题目中学习java语法

    一.输入输出 1.输入圆的半径,计算并输出圆的周长和面积: import java.util.Scanner; public class zuoye01_circle { public static ...

  8. css伪元素选择器

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. jQuery获取浏览器URL链接的值

    代码: 方法一: $.extend({ getUrlVars: function () { var vars = [], hash; ).split('&'); ; i < hashes ...

  10. Ubuntu14.04.1 阿里apt源

    deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiversedeb http://mirrors.a ...