一、原子操作
“读—修改—写”类型,访问同一存储器单元两次,第一次读原值,第二次写新值。当运行在两个CPU上的两个内核控制路径同时“读—修改—写”同一存储器单元,避免交错的“读—修改—写”,从而导致结果不对,使用原子操作,linux内核提供了一个专门的atomic_t类型(原子访问计数器)和一些专门的函数和宏。
1.原子整型操作
2.原子位操作
二、自旋锁
1.当一个线程获取了锁之后,其他试图获取这个锁的线程一直在循环等待获取这个锁,直至锁重新可用。由于线程是在一直循环的获取这个锁,所以会造成CPU处理时间的浪费,因此最好将自旋锁用于能很快处理完的临界区。
另外注意,一般来说,由自旋锁所保护的每个临界区都是禁止内核抢占的。自旋锁是不可递归的,递归请求会造成死锁。
在linux中,每个自旋锁都用spinlock_t结构表示,包含两个字段,
slock:表示自旋锁状态,值为1表示未加锁状态,负值和0,表示加锁状态。
break_lock:表示进程正在忙等自旋锁
2.自旋锁宏
3.读/写自旋锁
该锁除了和普通自旋锁一样,还有以下特点,
(1)读锁之间是共享的,即一个线程持有读锁之后,其他线程也可以以读的方式持有这个锁
(2)写锁之间是互斥的,即一个线程持有写锁之后,其他线程不能以读或写的方式持有这个锁
(3)读写锁之间是互斥的,即一个线程持有了读锁之后,其他线程不能以写的方式持有这个锁
三、顺序锁
该锁的特点是读锁被获取的时候,也允许写操作继续运行,这种策略的好处是写操作永远不会等待,缺点是有时候写操作不得不反复多次读相同的数据,直到获取有效副本。
do
{
/* 读之前获取 顺序锁foo 的序列值 */
seq = read_seqbegin(&foo);
...
} while(read_seqretry(&foo, seq)); /* 顺序锁foo此时的序列值!=seq 时返回true,反之返回false */
四、信号量
信号量也是一把锁,和自旋锁不同的是,信号量不会忙等,而是相应的进程或线程会被挂起,进入睡眠,只至信号量释放,资源才会变为可运行。
读/写信号量
读/写信号量类似于读/写自旋锁,不同的是,在信号量再次变为打开之前,等待进程挂起而不是自旋。
在学习中进步,如有错误,请多多批评指正