操作系统之自旋锁

自旋锁相关知识


自旋锁的功能以及使用方法和互斥锁极为相似。自旋锁与互斥锁的主要区别在于,当执行加锁操作时,如果当前锁不可用,对于自旋锁来说,则阻塞后不会让出cpu,会一直忙等待,直到得到锁。而对于互斥锁来说,阻塞后休眠让出cpu。

由于自旋锁不会睡眠,自旋锁一直占用cpu,在未获得锁的情况下,一直运行,所以占用着cpu,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低。因此,自旋锁通常用于驱动程序开发中,适合对短暂处理的资源进行加锁。

注意:在单处理器环境下,我们是不需要自旋锁,尽管调用了自旋锁的函数,里面也不是自旋锁的实现。

Linux系统中提供了如下几个函数来操作自旋锁:

函数 作用
pthread_spin_init 初始化一个自旋锁
pthread_spin_destroy 注销一个自旋锁
pthread_spin_lock 加锁操作,如果不成功,则阻塞等待
pthread_spin_trylock 测试加锁,如果不成功则立刻返回
pthread_spin_unlock 解锁操作

初始化自旋锁


使用自旋锁前必须先进行初始化操作。初始化自旋锁的库函数是pthread_spin_init。
pthread_spin_init函数的具体的说明如下:

需要的头文件:
#include

函数格式:
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
** 参数说明:
lock:自旋锁变量;
pshared:自旋锁属性

常见属性见下表;

属性值 意义
PTHREAD_PROCESS_SHARED 该自旋锁可以在多个进程中的线程之间共享
PTHREAD_PROCESS_PRIVATE 仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁

函数返回值说明: 调用成功,返回值总为0,否则返回一个非零的错误码。

加锁操作

对自旋锁初始化后,就可以给自旋锁进行加锁操作。Linux提供了两个库函数来对加锁,分别是:pthread_spin_lock和pthread_spin_trylock,这些函数的具体的说明如下:

需要的头文件:
#include 

函数格式:
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
参数说明:
lock:要被执行加锁操作的锁变量

函数返回值说明:
调用成功,返回值为0,否则,返回一个非零的错误码。

pthread_spin_lock和pthread_spin_trylock区别:
用pthread_spin_lock加锁时,如果lock已经被锁住,当前尝试加锁的线程就会被阻塞,直到自旋锁被其他线程释放。而pthread_spin_trylock函数则不同,如果lock已经被锁住,它将立即返回,返回的错误码为EBUSY,而不是阻塞等待。

解锁操作


有加锁操作就相对应的有解锁操作。Linux提供了一个pthread_spin_unlock函数来解锁操作,这个函数的具体的说明如下:

需要的头文件如下:
#include 

函数格式如下:
int pthread_spin_unlock(pthread_spinlock_t *lock);
参数说明:
lock:要被执行解锁操作的锁变量

函数返回值说明:
调用成功,返回值为0,否则返回一个非零的错误码。

注销锁操作


当一个自旋锁使用完毕后,必须进行清除。Linux提供了一个pthread_spin_destroy函数来注销一个自旋锁,这个函数的具体的说明如下:

需要的头文件如下:
#include 

函数格式如下:
int pthread_spin_destroy(pthread_spinlock_t *lock);
参数说明:
lock:要被执行注销操作的锁变量

函数返回值说明:
调用成功,返回值为0,否则返回一个非零的错误码。

案例:
编写一个程序,使用自旋锁对一个全局变量进行加锁。详细代码如下所示:

#include 
#include 
int globalNumber = 1;
//初始化一个普通自旋锁number_lock
pthread_spinlock_t number_lock;
void *addNumer(void *arg)
{
    pthread_spin_lock(&number_lock);
    globalNumber++;
    pthread_spin_unlock(&number_lock);
    return NULL;
}
int main()
{
    pthread_spin_init(&number_lock, PTHREAD_PROCESS_PRIVATE);
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, addNumer, NULL);	//创建进程
    pthread_create(&thread2, NULL, addNumer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("globalNumber = %d\n", globalNumber);
    pthread_spin_destroy(&number_lock);
    return 0;
}

结果
将以上代码保存为lockThread.c文件,编译执行。可以看到globalNumber变量变为了3,尽管我们不对globalNumber变量进行加锁,结果可能也是3,但是有可能出现结果为2的情况。

你可能感兴趣的:(操作系统)