(笔记)Linux内核学习(七)之内核同步机制和实现方式

一 原子操作

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

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锁(读写共享数据),顺序和屏障……

时间: 2024-10-27 20:40:21

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

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

一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页大小8KB 内核用相应的数据结构表示系统中的每个物理页: <linux/mm_types.h> struct page {} 内核通过这样的数据结构管理系统中所有的页,因此内核判断一个页是否空闲,谁有拥有这个页 ,拥有者可能是:用户空间进程.动态分配的内核数据.静态内核代码.页高速缓存-- 系统中

菜鸟笔记--Linux深入学习

一.(Linux下查找帮助,必须要了解的) Manual 帮助手册由 8 个章节组成,代表不同的内容.1. User commands (默认查看命令的帮助选项,供普通用户查看帮助说明文档. )2. System Calls (系统涵数调用帮助说明文件).3. Library calls (动太链接库帮助说明文件).4. Special files (系统设备帮助说明文件).5. File formats (格式帮助说明文件,提供常用文件编写格式说明).6. Games (游戏帮助说明文件).7

Linux 内核的同步机制,第 1 部分 + 第二部分(转)

http://blog.csdn.net/jk198310/article/details/9264721  原文地址: Linux 内核的同步机制,第 1 部分 一. 引言 在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上的执行单元对共享的数据的访问.在主流的Linux内核中包含了几乎所有现代的操作系统具有的同步机制,这些同步机制包括:原子操作

浅谈linux读写同步机制RCU

RCU是linux系统的一种读写同步机制,说到底他也是一种内核同步的手段,本问就RCU概率和实现机制,给出笔者的理解. [RCU概率] 我们先看下内核文档中对RCU的定义: RCU is a synchronization mechanism that was added to the Linux kernel during the 2.5 development effort that is optimized for read-mostly situations. 翻译:RCU是在2.5版本

linux 驱动学习笔记01--Linux 内核的编译

由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make config(基于文本的最为传统的配置界面,不推荐使用)#make menuconfig(基于文本菜单的配置界面)#make xconfig(要求 QT 被安装)#make gconfig(要求 GTK+被安装)在配置 Linux 2.6 内核所使用的 make config. make menuconfig. mak

Linux内核学习笔记——内核内存管理方式

一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页大小8KB 内核用相应的数据结构表示系统中的每个物理页: <linux/mm_types.h> struct page {} 内核通过这样的数据结构管理系统中所有的页,因此内核判断一个页是否空闲,谁有拥有这个页 ,拥有者可能是:用户空间进程.动态分配的内核数据.静态内核代码.页高速缓存…… 系统中

linux内核学习资料链接

1. 内核学习方法,编译.调试等常见问题1.1 关于编译升级内核到2.6.0的一些问题 作者:ommm        http://linux.chinaunix.net/bbs/thread-281831-1-5.html 1.2 VMWare Workstation 6.0调试Linux Kernel,竟如此方便 作者:albcamus        http://linux.chinaunix.net/bbs/thread-896214-1-5.html 1.3 基于S3C2410的Lin

Linux内核同步机制--转发自蜗窝科技

Linux内核同步机制之(一):原子操作 http://www.wowotech.net/linux_kenrel/atomic.html 一.源由 我们的程序逻辑经常遇到这样的操作序列: 1.读一个位于memory中的变量的值到寄存器中 2.修改该变量的值(也就是修改寄存器中的值) 3.将寄存器中的数值写回memory中的变量值 如果这个操作序列是串行化的操作(在一个thread中串行执行),那么一切OK,然而,世界总是不能如你所愿.在多CPU体系结构中,运行在两个CPU上的两个内核控制路径同

Linux网络编程&amp;内核学习

c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: (美)Greg Perry    [作译者介绍] 译者: 谢晓钢 刘艳娟 丛书名: 图灵程序设计丛书 C/C++系列 出版社:人民邮电出版社 ISBN:9787115216359上架时间:2009-12-10出版日期:2010 年1月开本:16开页码:308 说明:这本是入门最好的,最简单,最好懂 2.<