Linux系统编程-(pthread)线程通信(自旋锁)

简介: 自旋锁不管是内核编程,还是应用层编程都会用到;自旋锁和互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(也就叫自旋)状态。

1. 自旋锁介绍

自旋锁不管是内核编程,还是应用层编程都会用到;自旋锁和互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(也就叫自旋)状态。

自旋锁可用于下面的情况:锁被持有的时间短,并且线程不希望再重新调度上花费太多的成本。自旋锁通常作为底层原语用于实现其他类型的锁。根据他们所基于的系统架构,可以通过使用测试并设置指令有效地实现。当然这里说的有效也还是会导致CPU资源的浪费:当线程自旋锁变为可用时,CPU不能做其他任何事情,这也是自旋锁只能够被只有一小段时间的原因。

自旋锁总结:

  1. 自旋锁和互斥锁的使用框架、场景相似的。
  2. 互斥锁在得不到锁的时候会休眠。
  3. 自旋锁在得不到锁的时候不会休眠,会一直检测锁的状态。
  4. 自旋锁比较适合保护变量赋值、函数调用等场景。

2. 自旋锁相关接口函数

1. 销毁自旋锁
int   pthread_spin_destroy(pthread_spinlock_t *);
2. 初始化自旋锁
int   pthread_spin_init(pthread_spinlock_t *, int);
3. 自旋锁上锁(阻塞)
int   pthread_spin_lock(pthread_spinlock_t *);
4. 自旋锁上锁(非阻塞)
int   pthread_spin_trylock(pthread_spinlock_t *);
5. 自旋锁解锁
int   pthread_spin_unlock(pthread_spinlock_t *);
以上函数成功都返回0.

pthread_spin_init 函数的pshared参数表示进程共享属性,表明自旋锁是如何获取的,如果它设为PTHREAD_PROCESS_SHARED,则自旋锁能被,可以访问锁底层内存的线程所获取,即使那些线程属于不同的进程。否则pshared参数设为PTHREAD_PROCESS_PRIVATE,自旋锁就只能被初始化该锁的进程内部的线程访问到。

如果自旋锁当前在解锁状态,pthread_spin_lock函数不要自旋就可以对它加锁,试图对没有加锁的自旋锁进行解锁,结果是未定义的。需要注意,不要在持有自旋锁情况下可能会进入休眠状态的函数,如果调用了这些函数,会浪费CPU资源,其他线程需要获取自旋锁需要等待的时间更长了。

3. 自旋锁运用模板

下面代码创建了两个线程,分别访问一个全局变量,这里采用自旋锁进行保护。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>

pthread_spinlock_t spinlock;

int data;
/*
线程工作函数
*/
void *thread_work_func(void *dev)
{
    while(1)
    {
        pthread_spin_lock(&spinlock); //上锁
        printf("data=%d\n",data);
        pthread_spin_unlock(&spinlock); //解锁
        sleep(1);
    }
}

/*
线程工作函数
*/
void *thread_work_func2(void *dev)
{
    while(1)
    {
        pthread_spin_lock(&spinlock); //上锁
        data++;
        pthread_spin_unlock(&spinlock); //解锁
        sleep(1);
    }
}

int main(int argc,char **argv)
{   
    //初始化自旋锁
    pthread_spin_init(&spinlock,PTHREAD_PROCESS_PRIVATE);

    /*1. 创建子线程1*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("子线程1创建失败.\n");
        return -1;
    }
    /*2. 创建子线程2*/
    pthread_t thread_id2;
    if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0)
    {
        printf("子线程2创建失败.\n");
        return -1;
    }

    /*3. 等待线程的介绍*/
    pthread_join(thread_id,NULL);
    pthread_join(thread_id2,NULL);

    //销毁自旋锁
    pthread_spin_destroy(&spinlock);
    return 0;
}
目录
相关文章
|
4天前
|
Linux
Linux系统ext4磁盘扩容实践指南
这个过程就像是给你的房子建一个新的储物间。你需要先找到空地(创建新的分区),然后建造储物间(格式化为ext4文件系统),最后将储物间添加到你的房子中(将新的分区添加到文件系统中)。完成这些步骤后,你就有了一个更大的储物空间。
44 10
|
16天前
|
存储 缓存 Linux
Linux系统中如何查看CPU信息
本文介绍了查看CPU核心信息的方法,包括使用`lscpu`命令和读取`/proc/cpuinfo`文件。`lscpu`能快速提供逻辑CPU数量、物理核心数、插槽数等基本信息;而`/proc/cpuinfo`则包含更详细的配置数据,如核心ID和处理器编号。此外,还介绍了如何通过`lscpu`和`dmidecode`命令获取CPU型号、制造商及序列号,并解释了CPU频率与缓存大小的相关信息。最后,详细解析了`lscpu`命令输出的各项参数含义,帮助用户更好地理解CPU的具体配置。
56 8
|
16天前
|
存储 运维 监控
深度体验阿里云系统控制台:SysOM 让 Linux 服务器监控变得如此简单
作为一名经历过无数个凌晨三点被服务器报警电话惊醒的运维工程师,我对监控工具有着近乎苛刻的要求。记得去年那次大型活动,我们的主站流量暴增,服务器内存莫名其妙地飙升到90%以上,却找不到原因。如果当时有一款像阿里云 SysOM 这样直观的监控工具,也许我就不用熬通宵排查问题了。今天,我想分享一下我使用 SysOM 的亲身体验,特别是它那令人印象深刻的内存诊断功能。
|
1天前
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
54 27
|
6天前
|
存储 NoSQL Linux
微服务2——MongoDB单机部署4——Linux系统中的安装启动和连接
本节主要介绍了在Linux系统中安装、启动和连接MongoDB的详细步骤。首先从官网下载MongoDB压缩包并解压至指定目录,接着创建数据和日志存储目录,并配置`mongod.conf`文件以设定日志路径、数据存储路径及绑定IP等参数。之后通过配置文件启动MongoDB服务,并使用`mongo`命令或Compass工具进行连接测试。此外,还提供了防火墙配置建议以及服务停止的两种方法:快速关闭(直接杀死进程)和标准关闭(通过客户端命令安全关闭)。最后补充了数据损坏时的修复操作,确保数据库的稳定运行。
27 0
|
1月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
56 17
|
1月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
62 26
|
3月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
316 2
|
4月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
4月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####