线程同步——自旋锁

互斥量的工作原理
如果有多个线程同时访问临界资源,互斥量保证临界资源是被串行访问的。某个线程访问临界资源,线程首先给临界资源加锁,加锁好其他资源无法访问,其他线程只能等当前线程解锁后才能使用。

自旋锁

操作系统提供的API:pthread_spinlock_t

自旋锁的工作原理与互斥量一摸一样,也是在使用前加锁,使用完解锁保证串行访问。

自旋锁也是一种多线程同步的变量,使用了自旋锁的线程会反复的检查锁变量是否可用。如果不可用,就会一直循环的检查。所以自旋锁不会让出CPU,是一种忙等待状态。是死循环等待锁被释放。

自旋锁的优缺点

  1. 避免了进程或线程的上下文开销,如果锁占用时间不长,使用自旋锁代价很小
  2. 操作系统内部很多地方使用自旋锁
  3. 不适合在单核CPU使用,因为他等待时不会释放CPU,而是死循环等待。

生产者消费者模型

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>

pthread_spinlock_t spin_lock;

int num = 0;

void *producer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num += 1;
        pthread_spin_unlock(&spin_lock);
    }
}

void *comsumer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num -= 1;
        pthread_spin_unlock(&spin_lock);
    }
}


int main() {

    pthread_spin_init(&spin_lock, 0);
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, &producer, NULL);
    pthread_create(&thread2, NULL, &comsumer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("临界资源:%d",num)
    return 0;
}

不会让出cpu的demo,让消费者sleep10秒,生产者的自旋锁将会循环等待,查看此时的进程CPU是否为100%。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>

pthread_spinlock_t spin_lock;

int num = 0;

void *producer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num += 1;
        pthread_spin_unlock(&spin_lock);
    }
}

void *comsumer(void *) {
    int times = 10000000;
    while (times--) {
        pthread_spin_lock(&spin_lock);
        num -= 1;
        sleep(10);
        pthread_spin_unlock(&spin_lock);
    }
}


int main() {

    pthread_spin_init(&spin_lock, 0);
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, &producer, NULL);
    pthread_create(&thread2, NULL, &comsumer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("临界资源: %d\n", num);
    return 0;
}

备注:
代码中使用的是POSIX标准提供的编程接口,mac是没有的,所以在Mac下测试自旋锁是会出现报错的。 下图是Linux下已进程形式测试自旋锁cpp,可以看到spin_lock所使用的进程接近百分之百,说明自旋锁在运行的时候并不会让出CPU。
在这里插入图片描述
图片来源慕课网:《变成必备基础》

猜你喜欢

转载自blog.csdn.net/wankcn/article/details/108414562