Linux多线程同步方式
作者:网络转载 发布时间:[ 2015/2/12 13:57:41 ] 推荐标签:Linux 操作系统 线程
当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,可能出现偏差,得到与预期不符合的值。为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下;而操作系统对于多线程不会自动帮我们串行化,所以需要我们通过操作系统提供的同步方式api,结合自己的业务逻辑,利用多线程提高性能的同时,保证业务逻辑的正确性。一般而言,linux下同步方式主要有4种,原子锁,互斥量,读写锁和条件变量。下面一一介绍几种同步方式。
1. spinlock
1) 概念
spinlock是一种互斥结构,通过CPU提供的特殊的原子指令集合实现互斥地访问一个资源,需要硬件支持。一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。
2) 实现
spinlock一般基于原子的read-modify-write操作实现。read-modify-write操作允许一个CPU读取一个值,修改该值,并将修改完成的值回写内存的三个操作作为一个原子总线操作,因此需要CPU特殊支持。具体而言,通过test-and-set指令实现,从内存中读取一个值,然后和0比较,并且将内存中的值设置为1。
3) 相关函数
a) 原子操作
1 test_and_set(volatile int* addr, value)
2 {
3 return os_atomic_test_and_set_int(addr,value);
4 }
这里volatile修饰词告诉编译器从内存中获取,保证正确性,避免从寄存器中读取到不准确的值。
b) 设置锁变量
1 set_spinlock(lock_word)
2 {
3 int i = 0;
4 int value;
5 while (true)
6 {
7 value = test_and_set(&lock_word, 1);
8 if (value == 0) //尚未被占用,可以获取
9 break;
10 else //已经被其他线程占用,继续轮转
11 do nothing
12 }
13 }
c) 重置锁变量
1 reset_spinlock(lock_word)
2 {
3 test_and_set (lock_word, 0);
4 }
2. mutex
1) 概念
与 spinlock作用相同,保证互斥地访问一个资源。
2) 相关函数
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。
3) spinlock与mutex的区别
a) 作用范围,mutex是内核对象,可以在多线程,多进程同步中使用;spinlock作用范围于本进程(锁变量是进程内的),仅适用于多线程同步。
b) spinlock依赖于硬件的原子操作指令
c) 线程获取spinlock失败时,会采取循环等待的方式,此时线程处于运行状态,CPU空转;而获取mutex失败时,线程会挂起,线程处于wait状态,不会被内核调度。
d) 由于3的特点,进入等待状态或从等待状态被唤醒,都涉及到CPU的上下文切换,而CPU切换是比较耗时的,一般需要25us。相对而言spinlock则没有这样的代价,效率更高。
e) 也由于3的特点,spinlock会空转,导致浪费大量的CPU时间片,若用户持有锁时间长,导致空转时间长,也得不偿失。因此spinlock比较适合于“快拿快放”的使用场景。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11