linux---同步方法

1 原子操作

         内核提供了两组原子操作接口——一组针对整数进行操作,另一组针对单独的位进行操作。

1.1原子整数操作

        尽管Linux支持的所有机器上的整型数据都是32位的,但是使用atomic_t的代码只能将该类型当作24位来使用。(这里有疑问可以先不管

linux---同步方法_第1张图片

linux---同步方法_第2张图片

1.2 原子位操作

        由于原子位操作是对普通的指针进行操作,所以不像原子整型对应atomic_t,这里没有特殊的数据类型。相反,只要指针指向了任何你希望的数据,你就可以对它进行操作。来看一个例子:

linux---同步方法_第3张图片

linux---同步方法_第4张图片

2 自旋锁

自旋锁最多只能被一个可执行线程持有。如果一个执行线程试图获得一个被争用(已经被持有)的自旋锁,那么该线程就会一直进行忙循环——旋转——等待锁重新可用。

自旋锁的基本形式如下:

spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;

spin_lock(&mr_lock);

/*临界区*/

spin_unlock(&mr_lock);

警告:自旋锁是不可递归的!

Linux内核实现的自旋锁是不可递归的,这点不同于其他操作系统中的实现。所以如果你试图得到一个你正持有的锁,你必须自旋,等待你自己释放这个锁。但你处于忙等待中,所有你永远没有机会释放锁,于是你被自己锁死了。千万要小心自加锁。

自旋锁可以使用在中断处理程序中(此处不能使用信号量,因为它们会导致睡眠)。在中断处理程序中使用自旋锁时,一定要在获取锁之前,首先禁止本地中断(在当前处理器上的中断请求),否则中断处理程序就会打断持有锁的内核代码,有可能试图争用这个已经被持有的锁。这样一来,中断处理程序就会自旋,等待锁重新可用,但是锁的持有者在这个中断处理程序执行前不可能运行。这正是我们提到的双重请求死锁。

linux---同步方法_第5张图片

读写自旋锁

linux---同步方法_第6张图片

linux---同步方法_第7张图片

3 信号量

        Linux中的信号量是一种睡眠锁。如果有一个任务试图获得一个已经被占有的信号量时,信号量会将其推进一个等待队列,然后让其睡眠。这时处理器重获自由,从而去执行其他的代码。当持有信号量的进程将信号量释放后,处于等待队列中的那个任务将被唤醒,并获得该信号量。

linux---同步方法_第8张图片

计数信号量和互斥信号量。

3.1 信号量的使用

创建和初始化信号量:

linux---同步方法_第9张图片

使用信号量:

linux---同步方法_第10张图片

linux---同步方法_第11张图片

3.2 读写信号量

读写信号量在何种情况下使用,不太理解。

4 自旋锁和信号量

linux---同步方法_第12张图片

5 完成变量

完成变量仅仅提供了代替信号量的一个简单的解决方法。

linux---同步方法_第13张图片

6 BKL和seq锁

BKL是一种2.0向2.2过渡的锁,了解下即可。

SEQ锁是2.6内核新引进的一种锁机制,用于读写共享数据。实现这种锁主要依靠一个序列计数器。当有疑义的数据被写入时,会得到一个锁,并且序列值会增加。在读取数据之前和之后,序列号都被读取。如果读取的序列号值相同,说明在读操作过程中没有写操作打断过。此外,如果读取的值为偶数,那么久表明写操作没有发生(要明白因为锁的初值为0,所以写锁会使值为奇数,释放的时候又变成了偶数)。

linux---同步方法_第14张图片

7 禁止抢占

什么时候该禁止内核抢占?

这里书上讲的不好,以后在实际中体会吧!

linux---同步方法_第15张图片

8 顺序和屏障

linux---同步方法_第16张图片

你可能感兴趣的:(linux,运维,服务器)