Linux 同步机制:自旋锁

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/82721154
  1. 自旋锁(SpinLock):锁的目的是为了保护共享资源,实现线程同步。自旋锁区别于其他锁的地方在于若某线程在未获得锁时将不断的询问(判断)自旋锁保持者是否释放了锁(获取锁操作将自旋在那里,不断地申请获取,直到自旋锁保持者释放了锁),因此比较适用于保持锁时间比较短的情况(CPU一直在空转)。需要注意的是:一个锁只能有一个保持着。
  2. 互斥锁(Mutex): 某线程A获得互斥锁,可以访问共享资源,而当另一个线程B也要访问该共享资源时,发现互斥锁已经被线程A获得,那么B线程进入等待队列。若线程A释放了互斥锁,操作系统则在等待队列中唤醒一个需要互斥锁的线程。
  3. 信号量(semaphore): 在多线程环境下,用来保护共享资源。信号量有两个操作,P操作和V操作,一个计数器,计数器的值表示资源数。P操作使计数器减一,表示一个线程获得了一个资源,资源数减一。V操作是线程释放资源,计算器加一,也就是资源数加一。当计数器为零时,表示没有资源可供线程利用,此时,也没有线程等待资源。当再有线程申请该资源时,此时信号量为零,该线程则处于睡眠状态(放入等待队列)直到有线程执行V操作。整数信号量不能为负数,但记录型信号量可以为负数,负数的绝对值表示等待序列中线程的个数。这里的资源可以是打印机等。
  4. 临界区(critical section): 指一个访问共同资源的程序片段,访问临界资源的那段代码。简单来说,临界区是一段代码片段,这段代码片段能够访问共享资源。每次只能允许一个进程进入临界区,进入后不允许其他进程进入,其他进程处于等待状态(被挂起),进入临界区的进程要在有限时间内退出。

信号量/互斥体允许进程睡眠属于睡眠锁,自旋锁则不允许调用者睡眠,而是让其循环等待,所以有以下区别应用

1)、信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因而自旋锁适合于保持时间非常短的情况

2)、自旋锁可以用于中断,不能用于进程上下文(会引起死锁)。而信号量不允许使用在中断中,而可以用于进程上下文

3)、自旋锁保持期间是抢占失效的,自旋锁被持有时,内核不能被抢占,而信号量和读写信号量保持期间是可以被抢占的

总之,在用户态程序,极少有场景会适合用自旋锁。目前在实际工程中只见过涉及绑核的高性能转发有使用过,其他业务场景的同步基本靠互斥量和条件变量。

/*###################################  其他操作系统  ####################*/
//加锁一个自旋锁函数
void spin_lock(spinlock_t *lock);                                   //获取指定的自旋锁
void spin_lock_irq(spinlock_t *lock);                               //禁止本地中断获取指定的锁
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);      //保存本地中断的状态,禁止本地中断,并获取指定的锁
void spin_lock_bh(spinlock_t *lock)                                 //安全地避免死锁, 而仍然允许硬件中断被服务


//释放一个自旋锁函数
void spin_unlock(spinlock_t *lock);                                 //释放指定的锁
void spin_unlock_irq(spinlock_t *lock);                             //释放指定的锁,并激活本地中断
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); //释放指定的锁,并让本地中断恢复到以前的状态
void spin_unlock_bh(spinlock_t *lock);                              //对应于spin_lock_bh


//非阻塞锁
int spin_trylock(spinlock_t *lock);                  //试图获得某个特定的自旋锁,如果该锁已经被争用,该方法会立刻返回一个非0值,
                                                     //而不会自旋等待锁被释放,如果成果获得了这个锁,那么就返回0.
int spin_trylock_bh(spinlock_t *lock);                           
//这些函数成功时返回非零( 获得了锁 ), 否则 0. 没有"try"版本来禁止中断.

//其他
int spin_is_locked(spinlock_t *lock);               //和try_lock()差不多

/*###################################  linux  ####################*/
int pthread_spin_lock(pthread_spinlock_t *lock);     //上锁
int pthread_spin_trylock(pthread_spinlock_t *lock);   //自旋锁判断

int pthread_spin_unlock(pthread_spinlock_t *lock);   //释放自旋锁

int pthread_spin_destroy(pthread_spinlock_t *lock);   //清除自旋锁
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);   //解锁

实例代码:

#include <pthread.h>
#include <stdio.h>
#include <string.h>

char buff[100];
int buff_len;
pthread_spinlock_t spin;


void* th_writer(void *p)
{
    pthread_spin_lock(&spin);
    strcpy(buff, "hello, world!");
    printf("func[%s]: %s\n", __FUNCTION__, buff);
    pthread_spin_unlock(&spin);  // 释放缓冲区,共享的数据区
	pthread_exit( (void *)0 );
}

void* th_reader1(void *p)
{
    pthread_spin_lock(&spin);
    printf("func[%s]: %s\n", __FUNCTION__, buff);
    pthread_spin_unlock(&spin);
	pthread_exit( (void *)0 );
}

void* th_reader2(void *p)
{
    pthread_spin_lock(&spin);
    printf("func[%s]: %s\n", __FUNCTION__, buff);
    pthread_spin_unlock(&spin);
	pthread_exit( (void *)0 );
}

int main()
{
    pthread_t tid1, tid2, tid3;
    void *ret1, *ret2, *ret3;	
	
    pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);  //互斥量初始化
	                                                    //PTHREAD_PROCESS_PRIVATE   :表示只能由本进程访问
	                                                    //PTHREAD_PROCESS_SHARED    :表示可以由其他进程访问
    printf("start thread writer \n");
    pthread_create(&tid1, NULL, th_writer, NULL);   //创建 写 线程	
	
    printf("start thread reader 1\n");
    pthread_create(&tid2, NULL, th_reader1, NULL);  //创建 读 线程1
    printf("wait 1s in main thread.\n");	
	
    printf("start thread reader 2\n");
    pthread_create(&tid3, NULL, th_reader2, NULL);  //创建 读 线程2
	
    pthread_join(tid1, &ret1);
    pthread_join(tid2, &ret2);
    pthread_join(tid3, &ret3);
    pthread_spin_destroy(&spin);  //销毁自旋锁
    return 0;
}

结果:

# ./a.out 
start thread writer 
start thread reader 1
wait 1s in main thread.
start thread reader 2
func[th_writer]: hello, world!
func[th_reader1]: hello, world!
func[th_reader2]: hello, world!

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/82721154