LDD3学习笔记(8):并发和竞争

简介: 在计算机世界,百万分之一的事情会在几秒钟发生,并且问题的结果是严重的!1、并发的管理SMP(Symmetrical Multi-Processing)对称多处理机。

在计算机世界,百万分之一的事情会在几秒钟发生,并且问题的结果是严重的!

1、并发的管理

SMPSymmetrical Multi-Processing)对称多处理机。

竞争情况来自对共享资源的存取。

存取管理的常用技术是加锁或者互斥。

2、旗标的互斥体

当一个进程到了无法做进一步处理的时候,它就去睡眠(阻塞),让出处理器给别人知道以后某个时间它能够再做其他事情。

旗标是一个单个整型值,结合一对函数,成为PV,一个想要进入临界区的进程将在旗标上调用P,如果旗标的值大于0,这个值递减1并且进程继续,相反,如果旗标的值是0,进程必须等待直到别的进程释放旗标,解锁一个旗标通过调用V完成,这个函数递增旗标的值,如果需要,唤醒等待的进程。

旗标的使用需要包含<asm/semaphore.h>,相关类型是struct semaphore,直接创建一个旗标,使用sema_init来设定它:

Void sema_init(struct semaphore *sem,int val);

这里val是安排给旗标的初始值。

互斥锁模式的旗标:

DECLARE_MUTEX(name);

DECLARE_MUTEX_LOCKED(name);

这里name是一个旗标变量,前面是初始化为1,后面是初始化为0

互斥锁在运行时初始化使用下面中的一个:

Void init_MUTEX(struct semaphore *sem);

Void init_MUTEX_LOCKED(struct semaphore *sem);

3、completions(实现)机制

completion 是任务使用的一个轻量级机

允许一个线程告诉另一个线程工作已经完成。

completion 机制的典型使用是在模块退出时与内核线程的终止一起,当模块准备好被清理时, exit 函数告

知线程退出并且等待结束为此目的内核包含一个特殊的函数给线程使用:

void complete_and_exit(struct completion *c, long retval); 

4、自旋锁

一个自旋锁是一个互斥设备只能有 个值:"上锁""解锁". 它常常实现为一个整数值中的一个单个位想获取一个特殊锁的代码则测试相关的位如果锁是可用的这个"上锁"位被置位并且代码继续进入临界区相反如果这个锁已经被别人获得代码进入一个紧凑的循环中反复检查这个锁直到它变为可用这个循环就是自旋锁的"自旋"部分。

5、快速参考

本章已介绍了很多符号给并发的管理最重要的这些在此总结:

#include <asm/semaphore.h>

定义旗标和其上操作的包含文件.

DECLARE_MUTEX(name);

DECLARE_MUTEX_LOCKED(name);

个宏定义用来声明和初始化一个在互斥模式下使用的旗标.

void init_MUTEX(struct semaphore *sem);

void init_MUTEX_LOCKED(struct semaphore *sem);

这 函数用来在运行时初始化一个旗标.

void down(struct semaphore *sem);

int down_interruptible(struct semaphore *sem);

int down_trylock(struct semaphore *sem);

void up(struct semaphore *sem);

加锁和解锁旗标. down 使调用进程进入不可打断睡眠如果需要; down_interruptible, 相反可以被信号打断. down_trylock 不睡眠相反它立刻返回如果旗标不可用加锁旗标的代码必须最终使用 up 解锁它.

struct rw_semaphore;

init_rwsem(struct rw_semaphore *sem);

旗标的读者/写者版本和初始化它的函数.

void down_read(struct rw_semaphore *sem);

int down_read_trylock(struct rw_semaphore *sem);

void up_read(struct rw_semaphore *sem);

获得和释放对读者/写者旗标的读存取的函数.

void down_write(struct rw_semaphore *sem);

int down_write_trylock(struct rw_semaphore *sem);

void up_write(struct rw_semaphore *sem);

void downgrade_write(struct rw_semaphore *sem);

管理对读者/写者旗标写存取的函数.

#include <linux/completion.h>

DECLARE_COMPLETION(name);

init_completion(struct completion *c);

INIT_COMPLETION(struct completion c);

描述 Linux completion 机制的包含文件已经初始化 completion 的正常方法

INIT_COMPLETION 应当只用来重新初始化一个之前已经使用过的 completion. 

void wait_for_completion(struct completion *c);

等待一个 completion 事件发出.

void complete(struct completion *c);

void complete_all(struct completion *c);

发出一个 completion 事件. completion 唤醒最多一个等待着的线程而 complete_all 唤醒全

部等待者.

void complete_and_exit(struct completion *c, long retval);

通过调用 complete 来发出一个 completion 事件并且为当前线程调用 exit.

#include <linux/spinlock.h>

spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock_init(spinlock_t *lock);

定义自旋锁接口的包含文件以及初始化锁的 个方法.

void spin_lock(spinlock_t *lock);

void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);

void spin_lock_irq(spinlock_t *lock);

void spin_lock_bh(spinlock_t *lock);

加锁一个自旋锁的各种方法并且可能地禁止中断.

int spin_trylock(spinlock_t *lock);

int spin_trylock_bh(spinlock_t *lock);

上面函数的非自旋版本在获取锁失败时返回 0, 否则非零.

void spin_unlock(spinlock_t *lock);

void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);

void spin_unlock_irq(spinlock_t *lock);

void spin_unlock_bh(spinlock_t *lock);

释放一个自旋锁的相应方法.

rwlock_t lock = RW_LOCK_UNLOCKED

rwlock_init(rwlock_t *lock);

初始化读者/写者锁的 个方法.

void read_lock(rwlock_t *lock);

void read_lock_irqsave(rwlock_t *lock, unsigned long flags);

void read_lock_irq(rwlock_t *lock);

void read_lock_bh(rwlock_t *lock);

获得一个读者/写者锁的读存取的函数.

void read_unlock(rwlock_t *lock);

void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void read_unlock_irq(rwlock_t *lock);

void read_unlock_bh(rwlock_t *lock);

释放一个读者/写者自旋锁的读存取.

void write_lock(rwlock_t *lock);

void write_lock_irqsave(rwlock_t *lock, unsigned long flags);

void write_lock_irq(rwlock_t *lock);

void write_lock_bh(rwlock_t *lock);

获得一个读者/写者锁的写存取的函数.

void write_unlock(rwlock_t *lock);

void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void write_unlock_irq(rwlock_t *lock);

void write_unlock_bh(rwlock_t *lock);

释放一个读者/写者自旋锁的写存取的函数.

#include <asm/atomic.h>

atomic_t v = ATOMIC_INIT(value);

void atomic_set(atomic_t *v, int i);

int atomic_read(atomic_t *v);

void atomic_add(int i, atomic_t *v);

void atomic_sub(int i, atomic_t *v);

void atomic_inc(atomic_t *v);

void atomic_dec(atomic_t *v);

int atomic_inc_and_test(atomic_t *v);

int atomic_dec_and_test(atomic_t *v);

int atomic_sub_and_test(int i, atomic_t *v);

int atomic_add_negative(int i, atomic_t *v);

int atomic_add_return(int i, atomic_t *v);

int atomic_sub_return(int i, atomic_t *v);

int atomic_inc_return(atomic_t *v);

int atomic_dec_return(atomic_t *v);

原子地存取整数变量. atomic_t 变量必须只通过这些函数存取.

#include <asm/bitops.h>

void set_bit(nr, void *addr);

void clear_bit(nr, void *addr);

void change_bit(nr, void *addr);

test_bit(nr, void *addr);

int test_and_set_bit(nr, void *addr);

int test_and_clear_bit(nr, void *addr);

int test_and_change_bit(nr, void *addr);

原子地存取位值它们可用做标志或者锁变量使用这些函数阻止任何与并发存取这个位相关的竞争情况.

#include <linux/seqlock.h>

seqlock_t lock = SEQLOCK_UNLOCKED;

seqlock_init(seqlock_t *lock);

定义 seqlock 的包含文件已经初始化它们的 个方法.

unsigned int read_seqbegin(seqlock_t *lock);

unsigned int read_seqbegin_irqsave(seqlock_t *lock, unsigned long flags);

int read_seqretry(seqlock_t *lock, unsigned int seq);

int read_seqretry_irqrestore(seqlock_t *lock, unsigned int seq, unsigned long flags);

获得一个 seqlock-保护 的资源的读权限的函数.

void write_seqlock(seqlock_t *lock);

void write_seqlock_irqsave(seqlock_t *lock, unsigned long flags);

void write_seqlock_irq(seqlock_t *lock);

void write_seqlock_bh(seqlock_t *lock);

获取一个 seqlock-保护的资源的写权限的函数.

void write_sequnlock(seqlock_t *lock);

void write_sequnlock_irqrestore(seqlock_t *lock, unsigned long flags);

void write_sequnlock_irq(seqlock_t *lock);

void write_sequnlock_bh(seqlock_t *lock);

释放一个 seqlock-保护的资源的写权限的函数.

#include <linux/rcupdate.h>

需要使用读取-拷贝-更新(RCU)机制的包含文件.

void rcu_read_lock;

void rcu_read_unlock;

获取对由 RCU 保护的资源的原子读权限的宏定义.

void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg);

安排一个回调在所有处理器已经被调度以及一个 RCU-保护的资源可用被安全的释放之后运行.

 

目录
相关文章
|
8月前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
174 0
|
6月前
|
Python
解锁Python并发新世界:线程与进程的并行艺术,让你的应用性能翻倍!
【7月更文挑战第9天】并发编程**是同时执行多个任务的技术,提升程序效率。Python的**threading**模块支持多线程,适合IO密集型任务,但受GIL限制。**multiprocessing**模块允许多进程并行,绕过GIL,适用于CPU密集型任务。例如,计算平方和,多线程版本使用`threading`分割工作并同步结果;多进程版本利用`multiprocessing.Pool`分块计算再合并。正确选择能优化应用性能。
41 1
|
5月前
|
缓存 算法 关系型数据库
BP-Wrapper:无锁竞争的替换算法系统框架
BP-Wrapper:无锁竞争的替换算法系统框架
63 2
|
6月前
|
大数据 API 数据处理
Python高手都在用的并发秘籍:解锁线程与进程的终极奥义,性能飙升不是梦!
【7月更文挑战第8天】Python并发编程提升性能,线程(threading)适合I/O密集型任务,如网络请求,通过`start()`和`join()`实现并发。进程(multiprocessing)利用多核CPU,适用于CPU密集型任务,如大数据处理。结合两者可优化混合任务,实现最佳并发效果。
40 1
|
8月前
|
Rust 并行计算 安全
Rust中的并行与并发优化:释放多核性能
Rust语言以其内存安全和高效的并发模型在并行计算领域脱颖而出。本文深入探讨了Rust中的并行与并发优化技术,包括使用多线程、异步编程、以及并行算法等。通过理解并应用这些技术,Rust开发者可以有效地利用多核处理器,提高程序的性能和响应能力。
|
存储 缓存 Java
【并发技术12】线程锁技术的使用(二)
【并发技术12】线程锁技术的使用
|
Linux 调度
并发与竞争
并发与竞争
63 0
|
存储 缓存 安全
Go Mutex:保护并发访问共享资源的利器
本文主要介绍了 Go 语言中互斥锁 Mutex 的概念、对应的字段和方法、基本使用和易错场景,最后基于 Mutex 实现一个简单的线程安全的缓存。
228 0
Go Mutex:保护并发访问共享资源的利器
|
网络协议 安全 测试技术
协程并发(并行)资源竞争问题 | 学习笔记
快速学习协程并发(并行)资源竞争问题
协程并发(并行)资源竞争问题 | 学习笔记

热门文章

最新文章

相关实验场景

更多