Linux并发与竞争
Linux并发与竞争
Linux并发
并发是指在操作系统中,一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是 在同一个处理机上运行,但任一时刻点上只有一个程序在处理机上运行。 并发容易导致竞争问题。
Linux竞争
竞争就是两个或者多个进程同时访问一个资源,从而引起资源的错误。为避免并发对系统资源的影响。可以采用原子变量操作,自旋锁,信号量和互斥信号量。
原子变量操作
原子变量:
原子操作只能对整形变量或者位进行保护。
原子变量操作所谓原子变量操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断。也就是说,原子变量操作是一种不可以被打断的操作。原子操作需要硬件的支持,它们是使用汇编语言实现的,C语言并不能实现这样的操作。原子操作(包括原子整形操作和原子位操作)
原子操作:
typedef struct {int counter;
}atomic_t;
atomic_t a;原子整形操作 API 函数:
ATOMIC_INIT(int i) //定义原子变量的时候对其初始化。
int atomic_read(atomic_t *v) //读取 v 的值,并且返回。
void atomic_set(atomic_t *v, int i) //向 v 写入 i 值。
void atomic_add(int i, atomic_t *v) //给 v 加上 i 值。
void atomic_sub(int i, atomic_t *v) //从 v 减去 i 值。
void atomic_inc(atomic_t *v) //给 v 加 1,也就是自增。
void atomic_dec(atomic_t *v) //从 v 减 1,也就是自减
int atomic_dec_return(atomic_t *v) //从 v 减 1,并且返回 v 的值。
int atomic_inc_return(atomic_t *v) //给 v 加 1,并且返回 v 的值。
int atomic_sub_and_test(int i, atomic_t *v) //从 v 减 i,如果结果为 0 就返回真,否则返回假
int atomic_dec_and_test(atomic_t *v) //从 v 减 1,如果结果为 0 就返回真,否则返回假
int atomic_inc_and_test(atomic_t *v) //给 v 加 1,如果结果为 0 就返回真,否则返回假
int atomic_add_negative(int i, atomic_t *v) //给 v 加 i,如果结果为负就返回真,否则返回假原子位操作 API 函数:
void set_bit(int nr, void *p) //将 p 地址的第 nr 位置 1。
void clear_bit(int nr,void *p) //将 p 地址的第 nr 位清零。
void change_bit(int nr, void *p) //将 p 地址的第 nr 位进行翻转。
int test_bit(int nr, void *p) //获取 p 地址的第 nr 位的值。
int test_and_set_bit(int nr, void *p) //将 p 地址的第 nr 位置 1,并且返回 nr 位原来的值。
int test_and_clear_bit(int nr, void *p) //将 p 地址的第 nr 位清零,并且返回 nr 位原来的值。
int test_and_change_bit(int nr, void *p) //将 p 地址的第 nr 位翻转,并且返回 nr 位原来的值。
自旋锁
自旋锁:
在实际使用环境中,不可能只有整形变量或者位这么简单的临界区。当一个临界区域要在多个函数之间来回运行时,原子操作就显得无能为力了。
自旋锁:
typedef struct spinlock {......
}spinlock_t;
spinlock_t lock;自旋锁 API 函数:
DEFINE_SPINLOCK(spinlock_t lock) //定义并初始化一个自选变量。
int spin_lock_init(spinlock_t *lock) //初始化自旋锁。
void spin_lock(spinlock_t *lock) //获取指定的自旋锁,也叫做加锁。
void spin_unlock(spinlock_t *lock) //释放指定的自旋锁。
int spin_trylock(spinlock_t *lock) //尝试获取指定的自旋锁,如果没有获取到就返回 0
int spin_is_locked(spinlock_t *lock) //检查指定的自旋锁是否被获取,如果没有被获取就返回非 0,否则返回 0。使用自旋锁保护临界资源:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
临界资源代码
spin_unlock(&lock);使用自旋锁注意事项:
1.自旋锁是一种忙等待。Linux中,自旋锁当条件不满足时,会一直不断地循环条件是否被满足。如果满足,就解锁,继续运行下面的代码。这种忙等待机制对系统的性能是有影响的。所以在实际编程中,程序员应该注意自旋锁不应该长时间地持有,它是一种适合短时间锁定的轻量级的加锁机制。
2.自旋锁不能递归使用,这是因为,自旋锁被设计成在不同线程或者函数之间同步。如果一个线程在已经持有自旋锁时,其处于忙等待状态,则已经没机会释放自己持有的锁。如果这时再调用自身,则自旋锁永远没有执行的机会了。
信号量
信号量:
信号量与自旋锁的不同之处在于,自旋锁会忙等待。
而信号量会将进程加入到一个等待队列中去睡眠,直到拥有信号量的进程释放信号后,处于等待队列中的那个进程才会被唤醒。
当进程被唤醒后,就立刻重新从睡眠的地方开始执行,又一次试图获得信号量,当获取信号量后,程序继续执行。
从信号量的原理上来说,没有获得信号量的函数可能睡眠。这就要求只有能够睡眠的进程才能够使用信号量,不能睡眠的进程不能使用信号量。
例如在中断处理程序中,由于中断需要立刻完成,所以不能休眠,也就是说在中断处理函数程序中是不能使用信号量的。
信号量:
struct semaphore {raw_spinlock_t lock;unsigned int count;struct list_head wait_list;
};
struct semaphore sem;信号量 API 函数:
DEFINE_SEAMPHORE(name) //定义一个信号量,并且设置信号量的值为 1。
void sema_init(struct semaphore *sem, int val) //初始化信号量 sem,设置信号量值为 val。
void down(struct semaphore *sem) //获取信号量,因为会导致休眠,因此不能在中断中使用。
int down_trylock(struct semaphore *sem) //尝试获取信号量,如果能获取到信号量就获取,并且返回 0。如果不能就返回非 0,并且不会进入休眠。
int down_interruptible(struct semaphore *sem) //获取信号量,和 down 类似,只是使用 down 进入休眠状态的线程不能被信号打断。而使用此函数进入休眠以后是可以被信号打断的。
void up(struct semaphore *sem) //释放信号量使用信号量保护临界资源:
struct semaphore sem;
sema_init(&sem, 1);
down(&sem);
临界资源代码
up(&sem);信号量可以用于同步操作。
自旋锁和信号量的对比:
当被包含的代码能够在很短的时间内执行完成时,那么使用自旋锁是一种很好的选择。因为自旋锁只是忙等待,不会进入睡眠。睡眠是一种非常浪费时间的操作。
信号量用来在多个进程之间互斥。信号量的执行可能引起进程的睡眠,睡眠需要进程上下文的切换,这是非常浪费时间的一项工作。所以只有在一个进程对被保护的资源占用时间比进程切换的时间长很多时,信号量才是一种更好的选择。
互斥信号量
互斥信号量:
互斥体:
struct mutex {atomic_t count;spinlock_t wait_lock;
};
struct mutex lock;互斥体 API 函数:
DEFINE_MUTEX(name) //定义并初始化一个 mutex 变量。
void mutex_init(mutex *lock) //初始化 mutex。
void mutex_lock(struct mutex *lock)//获取 mutex,也就是给 mutex 上锁。如果获取不到就进休眠。
void mutex_unlock(struct mutex *lock) //释放 mutex,也就给 mutex 解锁。
int mutex_trylock(struct mutex *lock)//尝试获取 mutex,如果成功就返回 1,如果失败就返回 0。
int mutex_is_locked(struct mutex *lock)//判断 mutex 是否被获取,如果是的话就返回1,否则返回 0。
int mutex_lock_interruptible(struct mutex *lock) //使用此函数获取信号量失败进入休眠以后可以被信号打断。
Linux并发与竞争相关推荐
- Linux 并发与竞争
Linux是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况, 多个任务甚至中断都能访问的资源叫做共享资源,就和共享单车一样.在驱动开发中要注意对 共享资源的保护,也就是要处理对 ...
- 【正点原子MP157连载】第二十八章 Linux并发与竞争实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7
1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...
- STM32MP157驱动开发——Linux并发与竞争
STM32MP157驱动开发--Linux并发与竞争 一.相关知识 二.实现原子操作的一些方式 1.原子操作API ①整型数据原子操作 ②原子位操作API 2.自旋锁 3.其他类型的锁 ①读写自旋锁 ...
- linux 信号量 自旋锁 测试 实验,「正点原子Linux连载」第四十八章Linux并发与竞争实验...
1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南> 关注官方微信号公众号,获取更多资料:正点原子 第四十八章Linux并发与竞争实验 在上 ...
- Linux并发与竞争实验(一次只允许一个应用程序操作LED灯)
目录 原子操作实验 实验程序编写 运行测试(运行多个APP抢占资源) 自旋锁实验 实验程序编写 运行测试 信号量实验 实验程序编写 运行测试(第二条命令因为获取信号量失败而进入休眠状态) 互斥体实验( ...
- Linux并发与竞争介绍(原子操作、自旋锁、信号量、互斥体)
目录 并发与竞争 并发与竞争简介 保护内容是什么 原子操作 原子操作简介 原子整形操作API函数(atomic_t 结构体) 原子位操作API 函数 自旋锁 自旋锁简介 自旋锁API函数 线程与线程 ...
- 嵌入式Linux开发23——Linux并发与竞争
文章目录 并发与竞争 1.并发与竞争简介 2.保护内容 原子操作 1.原子操作简介 2.原子整形操作API函数 3.原子位操作API函数 自旋锁 1.自旋锁简介 2.自旋锁API函数 3.其他类型的锁 ...
- linux 两个驱动 竞争,Linux设备驱动第五章(并发和竞争)读书笔记(国外英文资料).doc...
Linux设备驱动第五章(并发和竞争)读书笔记(国外英文资料) Linux设备驱动第五章(并发和竞争)读书笔记(国外英文资料) The fifth chapter is concurrency and ...
- 并发与竞争(四)信号量
文章目录 信号量概念 概念 信号的工作方式 信号量的描述 信号量的API函数 信号量的注意事项 写代码 简单实现:信号量实现驱动只能被一个程序调用 完成代码 信号量概念 概念 两个特点: 信号量会引起 ...
最新文章
- mxnet加载resnet,进行预测
- MySql遇到字段中有空格
- 关于java.nio.Buffer的API
- 从 ThinkPHP 开发规范 看 PHP 的命名规范和开发建议
- Error opening terminal: xterm-256color
- JAVA面试常考系列一
- python网络编程知识点_python 网络编程要点
- 使用 Strace 和 GDB 调试工具的乐趣
- php-fpm进程利用CPU不均问题的优化过程
- c++ vscode 第三方库_请教下,vscode中怎么编译带第三方库的文件呢?谢谢! - C++程序设计语言 - CPlusPlus - 水木社区...
- 提高加密程序加密强度的技巧
- oracle 不等函数,Oracle 不常用函数
- Java无线数据增值业务概述
- Matlab Coder杂记
- 双显卡笔记本(Intel 集显Nvidia GEFORCE 920M显卡)配置ZED stereo camera
- 网站页面上标签页小图标的添加方式
- 黑白棋(人人对战)——C语言实现方法之一
- 17.Rust中函数式语言功能:迭代器与闭包
- 2015年9月11日
- Linux服务篇--openssh服务