OS-TEP: Fetch-And-Add

One final hardware primitive is the fetch-and-add instruction, which atomically increments a value while returning

the old value at a partucular address. The C presudocode for the fetch-and-add instruction looks like this:

int FetchAndAdd(int* ptr) {
         int old = *ptr;
         *ptr = old + 1;
         return old;
}

In this example, we will use fetch-and-add to build a more interesting ticket lock, as instroduced by Mellor-Crummey

and Scott. The lock and unlock looks like what you see in following figure.

typedef struct __lock_t {
           int ticket;
           int turn;
} lock_t;

void lock_init(lock_t* lock) {
           lock->ticket = 0;
           lock->turn   = 0;
}

void lock(lock_t* lock) {
           int myturn = FetchAndAdd(&lock->ticket);
           while (lock->turn == myturn)
                    ;
}

void unlock(lock_t* lock) {
           lock->turn = lock->turn + 1;
}

Instead of a signal value, this solution uses a ticket and tuen variable in combination to build a lock. The basic operation

is pretty simple: when a thread wishes to build a lock, it first does an atomic fetch-and-add on the ticket value; that

value is now considered this thread‘s turn. The globally shared lock->turn is then used to determine which thread‘s

turn it is; when myturn == turn for a given thread, it is that thread‘s turn to enter the critical section. Unlock is accomplished

simply by incrementing the turn such that the next waiting thread (if there is one) can now enter the critical section.

Note one important difference with this solution versus our previous attempts: it ensures progress for all threads. Once

a thread is assigned its ticket value, it will be scheduled at some point in the future (once these in front of it have passed

through the critical section and released the lock). In our previous attempt, no such guarantee existed; a thread

spining on test-and-set (for example) could spin forever even as other threads acquire and release the lock.

                Too Much Spinning: What Now ?

Our simple hardware-based locks are simple (only a few lines of code) and they work (you could even prove that

if you would like to, by writing some code), which are two excellent properties of any sytem or code. However, in

some cases, these solutions can be quite inefficient. Imagine you are running two threads on a single processor.

Now imagine that one thread (thread 0) is in a critical section and thus has a lock held, and unfortunately gets

interrupted. The second thread (thread 1) now tries to acquire the lock, but finds that it is held. Thus, it begins to

spin. And spin. Then it spins some mroe. And finally, a timer interrupt goes off, thread 0 is run again, which releases

the lock, and finally the next time it runs, thread 1 won‘t have to spin so much and will be able to acquire the lock.

Thus, any time a thread gets caught  spinning in a situation like this, it wastes an entire time slice doing nothing but

checking a value that is not going to change! The problem gets worse with N threads contending for a lock; N - 1

time slices may be wasted in a similar manner, simply spinning and waiting for a single thread to release the lock.

And thus, our next problem.

                    The Crux: How to avoid spinning

How can we develop a lock that does not needlessly waste time spinning on the CPU ?

Hardware support alone cannot solve this problem. We will need OS support too! Let‘s now figure out just how

that might work.

时间: 2024-11-02 21:36:01

OS-TEP: Fetch-And-Add的相关文章

python的 for dirpath, dirnames, filenames in os.walk(rs_path):

假设这三个目录三个文件放在 rs_path=d:/gmz 目录里面.那么要获取所有的文件路径,可以用如下方式 for parentpath, dirnames, filenames in os.walk(rs_path): for filename in filenames: print "filePath:" + parentpath + "/" + filename //这里总共会遍历四次,parentpath包含了所有文件父目录的可能即: d:/gmz/Bat

Python基础第12天

一:三级菜单直接退出的方法(tag的用法) tag=True while tag: print('level1') choice=input('level1>>: ').strip() if choice == 'quit':break if choice == 'quit_all': tag = False while tag: print('level2') choice=input('level2>>: ').strip() if choice == 'quit': brea

Python之路【第三篇】:Python基础(二)

Python之路[第三篇]:Python基础(二) 内置函数 一 详细见python文档,猛击这里 文件操作 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = file('文件路径', '模式') 注:python中打开文件有两种方式,即:open(...) 和  file(...) ,本质上前者在内部会调用后者来进行文件操作,推荐使用 open. 打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作.

python第五节

一.定义模块: 模块:用来从逻辑上组织python代码(变量.函数.类.逻辑:实现一个功能),本质就是以.py结尾的python文件(文件名:test.py ,对应的模块名就是test) 包:用来从逻辑上组织模块的,本质就是一个目录(必须带有__init__.py的文件)二.导入方法: 1.import module_XP#命名为module_XP.py#需要导入的模块内容#!/usr/bin/env python# -*- coding: utf-8 -*-# Author :XPname =

修改Haproxy文件配置,实现增删改查

Haproxy 源文件 global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 info defaults log global mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms option dontlognull listen stats :8888 stats enable stats uri /admi

python模块(六)

模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块. 如:os 是系统相关的模块:file是文件操作相关的模块 模块分为三种: 自定义模块 内置模块 开源模块 自定义模块 1.定义模块 情景一: 情景二: 情景三: 2.导入模块 Python之所以应用越来越广泛,在

day05

python开发 [五]字符串格式化和模块 简介: 本文内容包含: 1) 字符串格式化的两种方式 % 和format 2)模块: 模块简介: 模块使用: 常用模块的功能方法,如:os.sys.hashlib.用于序列化的json 和 pickle .shutil.ConfigParser.logging.time.re.random 一.  字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替

flag+文件操作

flag标志位,标识位,在其他语言中可能叫开关,个人觉得当作开关更容易理解.下面我们来利用这个开关来控制文件操作的流程,从而优雅的修改配置文件. global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 info defaults log global mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms optio

python作业----修改haproxy文件

global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 info defaults log global mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms option dontlognull listen stats :8888 stats enable stats uri /admin stats auth

模块整理笔记

1.模块定义 用来从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能),本质上就是.py结尾python文件 分类:内置模块.开源模块.自定义模块 2.导入模块 本质:导入模块的本质就是把python文件解释一遍:导入包的本质就是把包文件下面的init.py文件运行一遍 ① 同目录下模块的导入 #同级目录间import import module_name #直接导入模块 import module_name,module2_name #导入多个模块 使用:模块名.加函数名 fro