Linux应用 线程同步之自旋锁

1、概念

1.1 定义

自旋锁(Spinlock)是一种特殊的锁机制,当线程尝试获取锁而锁不可用时,线程会进入忙等待(即循环检查锁是否可用),而不是进入睡眠状态。这种机制适用于锁持有时间非常短的场景,因为它避免了线程上下文切换的开销。然而,如果锁持有时间较长,自旋锁可能会导致CPU资源的浪费。

1.2 特点

  • 忙等待:自旋锁会在获取锁时不断循环检查锁的状态,直到获取到锁为止。这种忙等待的方式可以减少线程切换的开销,适用于对锁的占用时间较短的情况。
  • 无阻塞:自旋锁不会将线程阻塞,因此适用于对锁的占用时间较短、竞争不激烈的情况。
  • 适用于多核CPU:自旋锁在多核CPU上效果更好,因为在一个核上的线程忙等待时,其他核上的线程可以继续执行。

1.3 应用场景

  • 短期占用:适用于对锁的占用时间较短的情况,避免线程切换的开销。
  • 低竞争:适用于竞争不激烈的情况,避免线程频繁地阻塞和唤醒。
  • 多核CPU:在多核CPU上,自旋锁的效率更高,因为可以充分利用多核并行执行的优势

2、常用接口

2.1 pthread_spin_init

初始化一个自旋锁。

pthread_spin_init(pthread_spinlock_t *lock, int pshared)
  • 入参
    • lock:指向要初始化的自旋锁的指针。
    • pshared:指定锁的共享属性,通常设置为PTHREAD_PROCESS_PRIVATE。
  • 返回值:若成功,返回0;否则返回错误码。

2.2 pthread_spin_lock

获取自旋锁。

pthread_spin_lock(pthread_spinlock_t *lock)
  • 入参
    • lock:指向要获取的自旋锁的指针。
  • 返回值:若成功,返回0;否则返回错误码。

2.3 pthread_spin_trylock

尝试获取自旋锁,如果锁已被其他线程占用,则立即返回。

pthread_spin_trylock(pthread_spinlock_t *lock)
  • 入参
    • lock:指向要尝试获取的自旋锁的指针。
  • 返回值:若成功获取锁,返回0;若锁已被占用,返回EBUSY;其他情况返回错误码。

2.4 pthread_spin_unlock

释放自旋锁。

pthread_spin_unlock(pthread_spinlock_t *lock)
  • 作用:释放自旋锁。
  • 入参
    • lock:指向要释放的自旋锁的指针。
  • 返回值:若成功,返回0;否则返回错误码。

2.5 pthread_spin_destroy

销毁一个已经初始化的自旋锁。

pthread_spin_destroy(pthread_spinlock_t *lock)
  • 作用:销毁一个已经初始化的自旋锁。
  • 入参
    • lock:指向要销毁的自旋锁的指针。
  • 返回值:若成功,返回0;否则返回错误码。

3、编程测试

分别测试使用自旋锁和不使用自旋锁操作全局变量的情况。定义一个全局共享变量shared_resource和两个线程都将访问并修改它。使用pthread_spinlock_t类型的变量spinlock作为自旋锁。在thread_function函数中,线程首先尝试使用pthread_spin_lock函数获取自旋锁,如果锁不可用,线程会忙等待直到锁可用。获取锁后,线程访问并修改共享资源,然后释放锁,使用pthread_spin_unlock函数。最后,主线程等待两个工作线程完成,并输出最终的共享资源值。

先将自旋锁代码注释掉,测试程序:

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
  
// 全局共享变量  
int shared_resource = 0;  
  
// 自旋锁  
pthread_spinlock_t spinlock;  
  
// 线程函数  
void* thread_function(void* arg) 
{  
    int thread_id = *(int*)arg;  
      
    // 尝试获取自旋锁  
    // pthread_spin_lock(&spinlock);  
      
    // 访问共享资源  
    for (int i = 0; i < 100000; i++) 
    {  
        shared_resource += 1;  
    }  
      
    printf("Thread %d finished, shared_resource = %d\n", thread_id, shared_resource);  
      
    // 释放自旋锁  
    // pthread_spin_unlock(&spinlock);  
      
    return NULL;  
}  
  
int main() 
{  
    // 初始化自旋锁  
    if (pthread_spin_init(&spinlock, 0) != 0) 
    {  
        printf("Spinlock initialization failed\n");  
        return 1;  
    }  
      
    // 创建两个线程  
    pthread_t thread1, thread2;  
    int thread1_id = 1, thread2_id = 2;  
    if (pthread_create(&thread1, NULL, thread_function, &thread1_id) != 0) 
    {  
        printf("Thread 1 creation failed\n");  
        return 1;  
    }  
    if (pthread_create(&thread2, NULL, thread_function, &thread2_id) != 0) 
    {  
        printf("Thread 2 creation failed\n");  
        return 1;  
    }  
      
    // 等待线程结束  
    pthread_join(thread1, NULL);  
    pthread_join(thread2, NULL);  
      
    // 销毁自旋锁  
    pthread_spin_destroy(&spinlock);  
      
    printf("Final shared_resource value: %d\n", shared_resource);  
      
    return 0;  
}

测试结果异常,结果不可控:

去掉注释测试自旋锁功能:

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
  
// 全局共享变量  
int shared_resource = 0;  
  
// 自旋锁  
pthread_spinlock_t spinlock;  
  
// 线程函数  
void* thread_function(void* arg) 
{  
    int thread_id = *(int*)arg;  
      
    // 尝试获取自旋锁  
    pthread_spin_lock(&spinlock);  
      
    // 访问共享资源  
    for (int i = 0; i < 100000; i++) 
    {  
        shared_resource += 1;  
    }  
      
    printf("Thread %d finished, shared_resource = %d\n", thread_id, shared_resource);  
      
    // 释放自旋锁  
    pthread_spin_unlock(&spinlock);  
      
    return NULL;  
}  
  
int main() 
{  
    // 初始化自旋锁  
    if (pthread_spin_init(&spinlock, 0) != 0) 
    {  
        printf("Spinlock initialization failed\n");  
        return 1;  
    }  
      
    // 创建两个线程  
    pthread_t thread1, thread2;  
    int thread1_id = 1, thread2_id = 2;  
    if (pthread_create(&thread1, NULL, thread_function, &thread1_id) != 0) 
    {  
        printf("Thread 1 creation failed\n");  
        return 1;  
    }  
    if (pthread_create(&thread2, NULL, thread_function, &thread2_id) != 0) 
    {  
        printf("Thread 2 creation failed\n");  
        return 1;  
    }  
      
    // 等待线程结束  
    pthread_join(thread1, NULL);  
    pthread_join(thread2, NULL);  
      
    // 销毁自旋锁  
    pthread_spin_destroy(&spinlock);  
      
    printf("Final shared_resource value: %d\n", shared_resource);  
      
    return 0;  
}

测试结果正常:

4、总结

本文讲解了Linux线程同步中使用的自旋锁的定义和应用场景,列举了编程中常用的接口,并编写测试用例进行测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466411.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习指标| 置信区间、Dice、IOU、MIOU、Kappa

深度学习部分指标介绍 置信区间混淆矩阵DiceIOU和MIOUKappa 置信区间 95%CI指标 读论文的时候&#xff0c;常会看到一个“95%CI”的评价指标。 其中CI指的是统计学中的置信区间&#xff08;Confidence interval&#xff0c;CI&#xff09;。在统计学中&#xff0c;一个概率样…

用python写网络爬虫:2.urllib库的基本用法

文章目录 urllib库抓取网页data参数timeout参数更灵活地配置参数登录代理Cookies 参考书籍 建议新入门的小伙伴先看我同一专栏的文章&#xff1a;用python写网络爬虫&#xff1a;1.基础知识 urllib库 urllib是python中一个最基础的HTTP库&#xff0c;一般是内置的&#xff0c;…

Linux网络基础2

目录 实现网络版本计算器 自己定协议实现用json协议实现 重谈OSI七层模型HTTP协议 域名介绍url介绍HTTP请求和响应 实现一个简易的HTTP服务器 实现简易Http服务器初级版实现简易Http服务器中级版 实现一个简易的HTTP服务器最终版 请求方法HTTP状态码HTTP常见的Header 实现网…

【鸿蒙HarmonyOS开发笔记】常用组件介绍篇 —— Progress进度条组件

概述 Progress为进度条组件&#xff0c;用于显示各种进度。 参数 Progress组件的参数定义如下 Progress(options: {value: number, total?: number, type?: ProgressType})● value value属性用于设置当前进度值。 ● total total属性用于设置总值。 ● type type属…

加拿大光量子计算公司Xanadu入局英国多企业量子合作计划

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 编辑丨慕一 编译/排版丨沛贤 深度好文&#xff1a;1200字丨8分钟阅读 英国航空发动机制造商罗尔斯罗伊斯&#xff08;Rolls-Royce&#xff09;、英国量子计算公司Riverlane和加拿大量子计算公…

【赠书】从深度学习到图神经网络:模型与实践

文章目录 赠书&#xff1a;《从深度学习到图神经网络&#xff1a;模型与实践》一、编辑推荐二、内容简介三、作者简介张玉宏杨铁军 四、精彩书评五、目录第1章 图上的深度学习 11.1 人工智能与深度学习 21.2 图神经网络时代的来临 61.3 图数据处理面临的挑战 91.4 图神经网络的…

AS-V1000视频监控平台如何加强系统安全,满足等保2.0规范要求

目 录 一、概述 &#xff08;一&#xff09;信息安全技术网络安全等级保护标准 &#xff08;二&#xff09;解读 1、等级保护工作的内容 2、等级保护的等级划分 3、不同等级的安全保护能力 第一级安全保护能力 第二级安全保护能力 第三级安全保护能力 第…

电子科技大学链时代工作室招新题C语言部分---题号D

1. 题目 这道题大概的意思就是对一个整形数组的元素进行排序&#xff0c;然后按新的顺序打印原本的下标&#xff1b; 例如&#xff0c;在题目给出的Note部分&#xff0c;{a1, a2, a3, a4, a5}进行排序之后变为了{a2, a1, a4, a3, a5}&#xff0c;于是输出2 1 4 3 5。 排序的规则…

MyBatisPlus中MetaObjectHandler的使用

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 起因是公司一个同事接到需求,让把一条数据录入时createTime字段,设置为…

DM数据库(docker)

docker安装 安装必要的系统工具 yum install -y yum-utils device-mapper-persistent-data lvm2 配置阿里云Docker Yum源: yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 更新yum缓存 yum makecache fast 安装docker-CE: y…

抛弃Superhuman?这些替代方案让你眼前一亮!

Superhuman是一个极好的人工智能工具在电子邮件助理领域。根据SimilarWeb的最新统计&#xff0c;它在全球网站排名中排名第21980位&#xff0c;月访问量为1751798。然而市场上还有许多其他优秀的选择。为了帮助您找到最适合您需求的解决方案&#xff0c;我们为您精心挑选了10种…

海淘注意事项,海淘虚拟卡

2024年海淘visa信用卡&#xff0c;点击获取卡片 海淘注意事项 海淘&#xff08;跨境购物&#xff09;可以让人们在国外购买到更多种类的商品&#xff0c;但是也需要注意一些事项&#xff0c;以确保购物的顺利进行和商品的质量。以下是一些建议&#xff1a; 海淘网站的选择&…

零代码编程:用kimichat合并一个文件夹下的多个文件

一个文件夹里面有很多个srt字幕文件&#xff0c;如何借助kimichat来自动批量合并呢&#xff1f; 在kimichat对话框中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;完成如下的编程任务&#xff1a; 这个文件夹&#xff1a;D:\downloads\life.on.our.planet.(202…

C++中的using关键字

1. 类型别名 using关键字可以用来为类型创建一个新的名字&#xff0c;这在代码的可读性和维护性方面非常有帮助。 // 定义类型别名 using IntPtr int*;// 使用 int value 5; IntPtr ptr &value;2. 命名空间别名 如果你正在使用一个非常长的命名空间&#xff0c;可以使…

如何在MT4平台查询自己的账户杠杆?

如何在MT4平台查询自己的账户杠杆?MT4中直接没有这个选项&#xff0c;犟嘴的投资者千万不要犟嘴&#xff0c;说可以根据保证金水平计算。其实在交易账户中有3中方法可以查询自己的账户&#xff0c;投资者可以在这里开立一个MT4帐户&#xff0c;并将其附加到具有登录名和密码的…

Jenkins-pipeline流水线构建完钉钉通知

添加钉钉机器人 在钉钉群设置里添加机器人拿出Webhook地址&#xff0c;设置关键词 Jenkins安装钉钉插件 Dashboard > 系统管理 > 插件管理&#xff0c;搜索构建通知&#xff0c;直接搜索Ding Talk也行 安装DingTalk插件&#xff0c;重启Jenkins 来到Dashboard > 系…

想要了解更多商品信息?淘宝天猫详情接口API助你一键搞定!

想要了解更多商品信息&#xff1f;淘宝天猫详情接口API是你的理想选择&#xff01;作为唯一提供官方商品数据的接口&#xff0c;它能够帮助你快速获取商品的多种详细信息&#xff0c;联讯数据让你在购物过程中做出更明智的决策。 简介&#xff1a;淘宝天猫详情接口API的功能及…

普通人搞副业,空闲时间做,月入5w+

我是电商珠珠 大家会发现&#xff0c;朱砂越来越火&#xff0c;不仅是因为它好看&#xff0c;而且商家对外扬言可以招财。现在的人对爱情不屑一顾&#xff0c;财神殿里可以长跪不起&#xff0c;人人都想求财&#xff0c;想要在空余时间搞副业赚大钱&#xff0c;但做什么还没有…

客服知识库到底好用在哪?企业真的需要吗?

在企业运营的众多环节中&#xff0c;客户服务无疑是至关重要的一环。然而&#xff0c;面对如洪水般涌入的客户问题和查询&#xff0c;你的客服团队是否能够做到快速应对&#xff0c;准确解答&#xff1f;这时&#xff0c;一个客服知识库就显得尤为重要。那么&#xff0c;客服知…

Java项目实战记录:雷达数据渲染

目录 Java项目实战记录&#xff1a;雷达数据渲染业务背景代码逻辑数据结构颜色渲染MapContent加载数据并输出截图 完整代码GenerateMapImage地图渲染工具测试代码 渲染效果 Java项目实战记录&#xff1a;雷达数据渲染 业务背景 我之前已经成功使用Java语言解析了C处理的雷达数…