百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

一文搞懂Linux线程同步原理(linux线程同步有几种方法)

citgpt 2024-08-01 13:31 8 浏览 0 评论

大家好,今天和大家聊一聊Linux线程同步相关的知识,线程同步相关的知识值得花时间好好研究,要设计出高性能软件架构,必须学好Linux线程同步,对Linux线程同步原理有深刻的认知。

1.背景知识

一文搞懂Linux线程同步原理(linux线程同步有几种方法)

1.1 原子变量和原子操作

原子变量和原子操作是多线程编程中的重要概念,用于保证多线程环境下的数据同步和互斥。原子操作是指不会被线程调度机制打断的操作,一旦开始就会一直运行到结束,中间不会切换到其他进程。原子变量是原子操作的基本单位。

C11标准引入了原子类型和原子操作,用于在多线程环境下保证数据的同步和一致性。

常见原子变量类型:

常见原子操作:

1.2 futex系统调用

futex是Linux内核提供的一种系统调用,用于实现用户空间线程之间的同步和互斥。它是fast userspace mutex的缩写,意为快速用户空间互斥锁。futex的主要作用是在用户空间实现锁和条件变量,避免了用户空间和内核空间之间的频繁切换,从而提高了多线程程序的性能。

futex系统调用的基本用法是:

  • 一个线程在需要锁或等待条件变量时,调用futex系统调用,将自己挂起。
  • 另一个线程在释放锁或改变条件变量时,调用futex系统调用,唤醒等待的线程。

1.2.1 futex函数原型

int futex(int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, int val3);

功能:futex函数是Linux内核提供的一种轻量级的锁机制,它可以用于用户空间进程间的同步。

参数:

uaddr:指向等待的变量的指针。

futex_op:表示要执行的操作,可以是以下值之一:

  • FUTEX_WAIT:等待变量的值变为指定值。
  • FUTEX_WAKE:唤醒等待变量的线程。

val:与操作相关的值。

timeout:超时时间。

uaddr2:第二个等待变量的指针。

val3:与第二个等待变量相关的值。

1.2.2 futex实现原理

通过futex系统调用执行FUTEX_WAIT命令,可以将线程挂起,futex传入的uaddr参数会通过hash函数转换成hash值,通过hash值能索引到futex_hash_bucket,此时会创建futex_q节点,futex_q节点会存储哈希key,线程相关信息,futex_q节点会插入chain链表。

通过futex系统调用执行FUTEX_WAKE命令可唤醒挂起线程,futex系统调用通过uaddr参数找到对应的futex_q节点,然后唤醒futex_q节点指向的挂起线程。

2.线程为什么需要同步?

Linux线程是在Linux操作系统中实现的一种轻量级进程,也称为轻量级进程或者LWP同一线程组的线程共享主线程(进程)的地址空间、文件描述符、信号处理等资源。

在Linux中,CPU的调度是以线程为单位进行调度的,因此线程的调度也是以线程为单位进行调度的。

由于线程之间共享地址空间,文件描述,信号相关资源,所以线程之间必然会存在同时访问同一资源的问题,如果不进行线程同步,就会导致数据的不一致性和安全性问题。同步可以保证在同一时刻只有一个线程访问共享资源,从而避免了数据的冲突和错误。

3. 互斥锁实现原理

互斥锁的实现视基于原子操作和futex系统调用实现。

3.1 互斥锁常见操作

  • 创建互斥锁

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  • 加锁

pthread_mutex_lock(&mutex);

  • 解锁

pthread_mutex_unlock(&mutex);

  • 尝试加锁

pthread_mutex_trylock(&mutex);

  • 销毁互斥锁

pthread_mutex_destroy(&mutex);

3.2 互斥锁实现原理

互斥锁本质是一个原子变量,原子变量同样是一个共享变量,不同的线程都能访问,只不过原子变量采用的是原子操作,互斥锁的操作不可被中断。

1)互斥锁初始化

将原子变量设置成0,原子变量不同的值代表锁不同的状态:

  • 原子变量等于0:互斥锁空闲,未加锁。
  • 原子变量等于1:互斥锁加锁成功。
  • 原子变量等于2:互斥锁加锁失败,线程通过futex(FUTEX_WAIT)系统调用被挂起。

2)互斥锁加锁

  • 通过atomic_compare_exchange_strong(value, 0, 1)原子操作,判断当前互斥锁是否已经被加锁,如果原子变量等于0,说明互斥锁空闲,此时可以对互斥锁进行加锁操作,将原子变量设置为1,返回true。
  • 如果原子变量不等于0,则说明互斥锁已经加锁,此时互斥锁加锁线程需要通过futex(FUTEX_WAIT)系统调用将线程挂起,挂起之前需要通过atomic_exchange(value, 2)设置原子变量的值为2,并返回旧原子变量值,通过旧原子变量值可以判断原子变量是否被其他线程操作。

3)互斥锁解锁

  • 线程通过atomic_exchange(value, 0)原子操作,将原子变量的值设置成0,返回旧原子变量值。
  • 如果旧原子变量的值等于2,说明有一个线程被挂起,此时需要通过futex(FUTEX_WAKE)系统调用唤醒挂起线程,解锁成功。
  • 如果旧原子变量小于等于1,则直接解锁成功。

总结:

互斥锁虽然有很多优点,能够很方便的进行线程同步,但是互斥锁是通过futex系统调用实现,采用系统调用必然存在用户态和内核态的切换问题,如果这种切换很频繁的话,必然会影响系统性能和降低系统效率,后续我们将继续探索更为高效的线程同步方式。


物联网心球(嵌入式软件开发专业内容生产者)。

C/C++,Linux Bug修复秘籍,Linux基础,Linux环境编程,Linux网络编程,高性能服务器,音视频开发,网络开发,Gui开发。

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: