Exercise1 源代码阅读

锁部分:spinlock.h/spinlock.c以及相关其他文件代码

// Mutual exclusion lock.
struct spinlock {
uint locked; // 0未被占用, 1已被占用 // For debugging:
char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock.
uint pcs[10]; // The call stack (an array of program counters)
// that locked the lock.
}; // 初始化自旋锁
void initlock(struct spinlock *lk, char *name)
{
lk->name = name;
lk->locked = 0;
lk->cpu = 0;
} // Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it.
void acquire(struct spinlock *lk)
{
// 关中断
pushcli(); // disable interrupts to avoid deadlock.
if(holding(lk)) // 判断锁的持有是否为当前cpu
panic("acquire"); // The xchg is atomic.
// It also serializes, so that reads after acquire are not
// reordered before it.
while(xchg(&lk->locked, 1) != 0); // 拿不到锁开始自旋 // Record info about lock acquisition for debugging.
lk->cpu = cpu;
getcallerpcs(&lk, lk->pcs);
} // Release the lock.
void release(struct spinlock *lk)
{
if(!holding(lk))
panic("release"); lk->pcs[0] = 0;
lk->cpu = 0; // The xchg serializes, so that reads before release are
// not reordered after it. The 1996 PentiumPro manual (Volume 3,
// 7.2) says reads can be carried out speculatively and in
// any order, which implies we need to serialize here.
// But the 2007 Intel 64 Architecture Memory Ordering White
// Paper says that Intel 64 and IA-32 will not move a load
// after a store. So lock->locked = 0 would work here.
// The xchg being asm volatile ensures gcc emits it after
// the above assignments (and after the critical section).
xchg(&lk->locked, 0); popcli();
}

Exercise2 带着问题阅读

1.什么是临界区? 什么是同步和互斥? 什么是竞争状态? 临界区操作时中断是否应该开启? 中断会有什么影响? XV6的锁是如何实现的,有什么操作? xchg 是什么指令,该指令有何特性?

  • 临界区(Critical Section):访问临界区的那段代码,多个进程/线程必须互斥进入临界区;
  • 同步(Synchronization):指多个进程/线程能够按照程序员期望的方式来协调执行顺序,为了实现这个目的,必须要借助于同步机制(如信号量,条件变量,管程等);
  • 互斥(Mutual Exclusion):互斥的目的是保护临界区;
  • 竞争状态:竞争是基于并发环境下的,单个进程/线程不存在竞争,在并发环境下,多个进程/线程都需要请求某资源的时候,只有竞争到该资源的进程/线程才能够执行,释放资源后,剩余进程/线程按照预定的算法策略重新竞争;
  • 操作临界区必须关中断,对临界区的操作是原子性的;
  • 中断影响:中断降低了并发性能,同时中断也会导致频繁的上下文切换,上下文切换会导致tlb快表失效,因此要尽可能的缩减中断处理的时间;
  • 自旋锁(Spinlock):xv6中利用该数据结构实现多个进程/线程同步和互斥访问临界区。当进程/线程请求锁失败时进入循环,直至锁可用并成功拿到后返回,对于单cpu系统自旋锁浪费CPU资源,不利于并发,自旋锁的优势体现在多CPU系统下,XV6支持多CPU。主要接口有void initlock(struct spinlock * lk, char * name)、void initlock(struct spinlock * lk, char * name)、void release(struct spinlock * lk);
  • xchg:xchg()函数使用GCC的内联汇编语句,该函数中通过xchg原子性交换spinlock.locked和newval,并返回spinlock.locked原来的值。当返回值为1时,说明其他线程占用了该锁,继续循环等待;当返回值为0时,说明其他地方没有占用该锁,同时locked本设置成1了,所以该锁被此处占用。
// x86.h 调用方式如xchg(&lk->locked, 1)
static inline uint xchg(volatile uint *addr, uint newval)
{
uint result; // The + in "+m" denotes a read-modify-write operand.
asm volatile("lock; xchgl %0, %1" :
"+m" (*addr), "=a" (result) :
"1" (newval) :
"cc");
return result;
}

2.基于XV6的spinlock, 请给出实现信号量、读写锁、信号机制的设计方案(三选二,请写出相应的伪代码)?

  • 信号量实现
struct semaphore {
int value;
struct spinlock lock;
struct proc *queue[NPROC]; // 进程等待队列,这是一个循环队列
int end; // 队尾
int start; // 队头
}; // 初始化信号量
void sem_init(struct semaphore *s, int value) {
s->value = value;
initlock(&s->lock, "semaphore_lock");
end = start = 0;
} void sem_wait(struct semaphore *s) {
acquire(&s->lock); // 竞争锁,如果竞争不到进入自旋
s->value--;
if (s->value < 0) {
s->queue[s->end] = myproc(); // myproc()获取当前进程, 放入队尾
s->end = (s->end + 1) % NPROC; // 循环队列计算新的队尾
// 1. 释放锁(下一个sem_wait的进程才能进入acquire),
// 2. 然后进入睡眠等待, 被唤醒时重新竞争锁
sleep(myproc(), &s->lock);
}
release(&s->lock);
} void sem_signal(struct semaphore *s) {
acquire(&s->lock); // 竞争锁
s->value++;
if (s->value <= 0) {
wakeup(s->queue[s->start]); // 唤醒循环队列头的进程
s->queue[s->start] = 0;
s->start = (s->start + 1) % NPROC; // 重新计算队头
}
release(&s->lock);
} // proc.h
// Per-process state
struct proc {
uint sz; // Size of process memory (bytes)
pde_t* pgdir; // Page table
char *kstack; // Bottom of kernel stack for this process
enum procstate state; // Process state
volatile int pid; // Process ID
struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall
struct context *context; // swtch() here to run process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
};

参考文献

[1] xv6锁-博客园

[2] xv6锁-xchg

[3] xv6锁-CSDN

[4] xv6整体报告-百度文库

XV6源代码阅读-同步机制的更多相关文章

  1. XV6源代码阅读-文件系统

    Exercise1 源代码阅读 文件系统部分 buf.h fcntl.h stat.h fs.h file.h ide.c bio.c log.c fs.c file.c sysfile.c exec ...

  2. XV6源代码阅读-虚拟内存管理

    Exercise1 源代码阅读 1.内存管理部分: kalloc.c vm.c 以及相关其他文件代码 kalloc.c:char * kalloc(void)负责在需要的时候为用户空间.内核栈.页表页 ...

  3. XV6源代码阅读-中断与系统调用

    Exercise1 源代码阅读 1.启动部分: bootasm.S bootmain.c 和xv6初始化模块:main.c bootasm.S 由16位和32位汇编混合编写成的XV6引导加载器.boo ...

  4. XV6源代码阅读-进程线程

    Exercise1 源代码阅读 1.基本头文件:types.h param.h memlayout.h defs.h x86.h asm.h mmu.h elf.h types.h:仅仅是定义uint ...

  5. Mongodb源代码阅读笔记:Journal机制

    Mongodb源代码阅读笔记:Journal机制 Mongodb源代码阅读笔记:Journal机制 涉及的文件 一些说明 PREPLOGBUFFER WRITETOJOURNAL WRITETODAT ...

  6. nginx源代码分析--进程间通信机制 &amp; 同步机制

    Nginx源代码分析-进程间通信机制 从nginx的进程模型能够知道.master进程和worker进程须要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号, ...

  7. MySQL系列:innodb源代码分析之线程并发同步机制

    innodb是一个多线程并发的存储引擎,内部的读写都是用多线程来实现的,所以innodb内部实现了一个比較高效的并发同步机制. innodb并没有直接使用系统提供的锁(latch)同步结构,而是对其进 ...

  8. Chromium Graphics: GPUclient的原理和实现分析之间的同步机制-Part I

    摘要:Chromium于GPU多个流程架构的同意GPUclient这将是这次访问的同时GPU维修,和GPUclient这之间可能存在数据依赖性.因此必须提供一个同步机制,以确保GPU订购业务.本文讨论 ...

  9. pthread的各种同步机制

    https://casatwy.com/pthreadde-ge-chong-tong-bu-ji-zhi.html pthread是POSIX标准的多线程库,UNIX.Linux上广泛使用,wind ...

随机推荐

  1. DHT协议网络爬虫磁力链接和BT种子搜索引擎

    系统功能和用到的技术. 系统包括几个独立的部分: 使用 Python 的 Scrapy 框架开发的网络爬虫,用来爬取磁力链接和种子: 使用 PHP CI 框架开发的简易网站: 搜索引擎目前直接使用的 ...

  2. 单链表 C++ 实现 - 含虚拟头节点

    本文例程下载链接:ListDemo 链表 vs 数组 链表和数组的最大区别在于链表不支持随机访问,不能像数组那样对任意一个(索引)位置的元素进行访问,而需要从头节点开始,一个一个往后访问直到查找到目标 ...

  3. GO闭包

    package main import "fmt" func main() { add_func := add(1,2) fmt.Println(add_func(1,1)) fm ...

  4. python爬虫(七) mozillacookiejar

    MozillaCookiejar 保存百度得Cookiejar信息: from urllib import request from urllib import parse from http.coo ...

  5. STM32的程序升级

    IAP基础参考http://www.eeworld.com.cn/mcu/2018/ic-news112042038.html https://blog.csdn.net/tq384998430/ar ...

  6. XModem与YModem

    XModem用在串口异步传文件: #define SOH 0x01 #define STX 0x02 #define EOT 0x04 #define ACK 0x06 #define NAK 0x1 ...

  7. 【PAT甲级】1018 Public Bike Management (30 分)(SPFA,DFS)

    题意: 输入四个正整数C,N,S,M(c<=100,n<=500),分别表示每个自行车站的最大容量,车站个数,此次行动的终点站以及接下来的M行输入即通路.接下来输入一行N个正整数表示每个自 ...

  8. Java中正确使用hashCode和equals方法

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...

  9. The way get information from mssql by using excel vba and special port

    Yes,  we can get information from mssql by using excel vba.  But the default port of MSSQL is  1433. ...

  10. 四 动态sql 标签的使用(if&where&sql片段&foreach)

    if标签的使用: userMapper.xml  userMapper.java junit: where标签: 注意:写了where标签就不用手动写where语句 sql片段的设置和调用: forr ...