当前位置: 首页 > news >正文

嵌入式Linux:线程同步(自旋锁)

目录

1、自旋锁初始化与销毁

2、自旋锁加锁与解锁


Linux 自旋锁(spinlock)是一种用于保护共享资源的锁机制,常用于多核处理器中,在某个核(或线程)试图获取锁时,如果发现锁已被其他核持有,它会忙等(不断循环检查)而不是让出 CPU 时间片。自旋锁的特点是适用于锁的持有时间非常短的场景,因为它在等待期间不会主动放弃 CPU,而是不断尝试获取锁,这在多核系统中可以避免由于线程调度带来的上下文切换开销。

工作原理:

  • 加锁:线程尝试获取锁,如果成功,则进入临界区。如果锁已经被占用,线程会不停地轮询检查锁是否释放。
  • 忙等(自旋):如果锁被占用,线程会持续忙等,不会主动让出 CPU。这样避免了上下文切换,但消耗了 CPU 资源,因此自旋锁适用于锁定时间较短的场景。
  • 解锁:当临界区的任务完成后,线程释放锁,其他正在忙等的线程可以继续尝试获取锁。

自旋锁常用于以下情况:

  • 需要保护的代码段执行时间非常短,能够迅速释放锁。
  • 不希望线程进入睡眠状态或导致上下文切换,尤其是在内核中的中断处理程序或者性能要求高的系统。
  • 多核系统中,并发访问的共享资源保护,避免线程在上下文切换中浪费时间。

自旋锁与互斥锁的比较如下:

实现方式上的区别

  • 自旋锁是一种轻量级锁机制,它本质上是在忙等状态下获取锁。当线程无法获取锁时,线程不会进入睡眠或等待状态,而是会不断地检查锁的状态,直到可以成功获取锁。
  • 互斥锁则是一种更高层的锁,通常在无法获取锁时会导致线程进入阻塞状态。互斥锁可以让操作系统将当前线程挂起,等待锁可用时再唤醒。

开销上的区别

  • 自旋锁的主要优势在于没有上下文切换的开销,特别适用于锁持有时间很短的场景。由于自旋锁不会导致线程休眠,所以在处理器繁忙时可能会浪费 CPU 时间。如果等待时间较长,忙等会消耗过多的 CPU 资源,反而导致效率下降。
  • 互斥锁的开销较大,因为线程在获取不到锁时会陷入休眠,直到获取到锁时才会被唤醒。休眠和唤醒的代价很高,特别是在频繁锁定/解锁的场景中会影响性能。

适用场景上的区别

  • 自旋锁常用于内核中或者需要避免上下文切换的场景。特别是在中断上下文中,自旋锁更为合适,因为中断处理程序不能被阻塞或休眠。它适用于那些执行时间极短的临界区,锁的持有时间必须足够短,才能避免因自旋导致 CPU 资源浪费。
  • 互斥锁更适用于用户态的程序或者锁定时间较长的临界区。当程序无法获取到互斥锁时,系统可以调度其他线程运行,直到锁被释放,适合长时间的等待操作。

死锁问题

  • 如果对同一个自旋锁进行两次加锁操作,必然会导致死锁,因为自旋锁不具备递归性。
  • 互斥锁则可以通过特定的类型来避免死锁。例如 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁在检测到重复加锁时,会返回错误而不是陷入死锁状态。

1、自旋锁初始化与销毁

自旋锁需要在使用前进行初始化,并在不再使用时销毁。

初始化自旋锁函数如下:

#include <pthread.h>
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);

参数

  • lock:指向需要初始化的自旋锁对象。
  • pshared:自旋锁的共享属性,可以取值:
    • PTHREAD_PROCESS_SHARED:允许在多个进程中的线程之间共享自旋锁。
    • PTHREAD_PROCESS_PRIVATE:自旋锁只能在同一进程内的线程之间使用。

返回值:成功时返回 0,失败时返回非零错误码。

销毁自旋锁函数如下:

int pthread_spin_destroy(pthread_spinlock_t *lock);

参数lock:指向要销毁的自旋锁对象。

返回值:成功时返回 0,失败时返回非零错误码。

2、自旋锁加锁与解锁

加锁函数如下:

int pthread_spin_lock(pthread_spinlock_t *lock);

参数lock:指向要加锁的自旋锁对象。

返回值:成功时返回 0;如果锁已经被其他线程占用,则线程会忙等,直到成功获取锁,最终返回 0

尝试加锁函数如下:

int pthread_spin_trylock(pthread_spinlock_t *lock);

参数lock:指向要加锁的自旋锁对象。

返回值

  • 成功时返回 0
  • 如果锁已被占用,立即返回 EBUSY

解锁函数如下:

int pthread_spin_unlock(pthread_spinlock_t *lock);

参数lock:指向要解锁的自旋锁对象。

返回值:成功时返回 0,失败时返回非零错误码。

下面是一个完整的示例,展示如何使用自旋锁,包括初始化、加锁、解锁和销毁:

#include <pthread.h>
#include <stdio.h>pthread_spinlock_t spinlock; // 定义自旋锁
int shared_data = 0; // 共享数据void *thread_func(void *arg) {pthread_spin_lock(&spinlock); // 加锁shared_data++;printf("Thread %ld: shared_data = %d\n", (long)arg, shared_data);pthread_spin_unlock(&spinlock); // 解锁return NULL;
}int main() {pthread_t threads[2];// 初始化自旋锁if (pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE) != 0) {perror("Failed to initialize spinlock");return 1;}// 创建两个线程pthread_create(&threads[0], NULL, thread_func, (void *)1);pthread_create(&threads[1], NULL, thread_func, (void *)2);// 等待线程结束pthread_join(threads[0], NULL);pthread_join(threads[1], NULL);// 销毁自旋锁if (pthread_spin_destroy(&spinlock) != 0) {perror("Failed to destroy spinlock");return 1;}return 0;
}

自旋锁的主要问题在于,它在获取不到锁时不会释放 CPU,而是持续消耗资源。如果锁持有时间较长,CPU 的利用效率会急剧下降。因此,自旋锁不适合用于长时间锁定的场景,只适合那些临界区极短的操作。

通过对 pthread_spin_* 函数的合理使用,可以有效管理多线程访问共享资源的同步问题。确保在适当的地方进行加锁和解锁,以防止死锁和资源竞争。

http://www.dtcms.com/a/560920.html

相关文章:

  • RHCE复习第一次作业
  • 2025年山西省职业院校技能大赛应用软件系统开发赛项竞赛样题
  • 铁路机车乘务员心理健康状况的研究进展
  • 人才市场官方网站装修公司网站平台
  • Flink 2.1 SQL:解锁实时数据与AI集成,实现可扩展流处理
  • 【软件安全】什么是AFL(American Fuzzy Lop)基于覆盖率引导的模糊测试工具?
  • 山西省最新干部调整佛山网站建设优化
  • 背包DP合集
  • Docker 拉取镜像:SSL 拦截与国内镜像源失效问题解决
  • full join优化改写经验
  • 软件测试:黑盒测试用例篇
  • 【Linux】Linux第一个小程序 - 进度条
  • ubuntu新增用户
  • 青州市网站建设长沙招聘网58同城招聘发布
  • 江苏中南建设集团网站是多少长沙互联网网站建设
  • 从零开始的云原生之旅(十一):压测实战:验证弹性伸缩效果
  • 民宿网站的建设wordpress gallery
  • 【开题答辩全过程】以 广州网红点打卡介绍网站为例,包含答辩的问题和答案
  • Taro 源码浅析
  • Chart.js 混合图:深度解析与应用技巧
  • redis 大key、热key优化技巧|空间存储优化|调优技巧(一)
  • 监视你的脚本:自动 Linux 活动审计
  • 15.1.2.linux常见操作用例
  • 【Java Web学习 | 第五篇】CSS(4) -盒子模型
  • ubuntu samba 快速安装启用
  • 【数据结构】用顺序表实现通讯录
  • cpp / c++零基础就业学习一站式学习平台
  • FreeRTOS(二)
  • 开源AI智能名片链动2+1模式S2B2C商城小程序商业化路径优化研究
  • 中国优秀的企业网站做搜狐网站页面