首页 > 编程知识 正文

竞争互斥原理,同步和互斥的区别

时间:2023-05-05 10:48:06 阅读:162442 作者:558

零,前言所谓的锁,在计算机里本质上就是一块内存空间。此空间分配给1时表示锁定已解除,分配给0时表示锁定已解除。 就这样了。

多个线程夺取一个锁就是剥夺将这个内存分配给1。 在多核环境中,内存空间是共享的,每个内核都有一个线程在运行。 如何确保一次只能有一个线程成功获得锁呢? 您可能已经注意到了,这需要硬件的某种保证。

对于单核,可以通过关闭CPU中断以暂停当前请求使其无法处理其他请求来分配相应的内存空间。

对于多核,锁定总线一致性技术(请参阅此处)允许单个CPU中只有一个内核分配并“锁定”相应的内存空间,从而实现锁定。

实际上,mutex的基础实现API是Futex。

一、什么是Futex? Futex是快速用户空间矩阵的缩写。

Futex用英语翻译的话,就是高速用户空间互斥体。 其设计思想其实是在传统的Unix系统中,诸如system vipc (内部进程通信)、semaphores、msgqueues、sockets (子进程间同步)等进程间同步机制都是然而,研究表明,许多同步是不竞争的。 也就是说,在某个进程进入独占区域和从某个独占区域出来之间,即使没有进程,也经常进入此独占区域或请求相同的同步变量。 但是,在这种情况下,该进程也必须陷入内核,调查是否有人在竞争,结束时陷入内核,调查进程是否在等待同一个同步变量。 这些不必要的系统调用(即内核陷入)会产生大量的性能开销。

为了解决这个问题,Futex应运而生。 Futex是一种用户状态和内核状态混合的同步机制。 首先,在同步的进程之间通过mmap共享内存。 futex变量位于此共享内存中,操作是原子的。 当进程要进入独占区或退出独占区时,首先要去看共享内存中的futex变量,如果没有冲突,只修改futex,不需要执行系统调用。 如果您访问futex变量以告知进程发生了冲突,则必须执行系统调用以完成相应的操作(wait或wake up )。 简单地说,通过检查用户状态,如果发现没有(motivation )冲突,futex就不需要陷入内核,从而大大提高了低内容的效率。 Linux支持2.5.7到Futex。

二、Futex系统调用Futex是一种用户状态和内核状态的混合机制,需要两个部分协同完成。 在linux上提供了sys_futex系统调用,支持进程冲突时的同步处理。 原型和呼叫号码是

# include Linux/futex.h # includesys/time.hint futex (int * uaddr,int op,int val,const struct timespec *timeout,timeout,int 其他的东西也经常被ignore。

uaddr是用户状态的共享存储器的地址,内部排列存储有整数计数器。

op保存着操作类型。 的定义有5种,这里简单介绍2种,剩下的感兴趣的自己去man futex

FUTEX_WAKE :原子检查uaddr中计数器的值是否为val,如果是,则停止过程,直到达到FUTEX_WAKE或超时(time-out )。 也就是说,将进程乘以与uaddr对应的队列。

FUTEX_WAKE :调用最多val个uaddr上的进程等待。

您可以看到FUTEX_WAIT和FUTEX_WAKE只是用于挂起或唤醒进程。 当然,这部分的工作也只能在内核状态下进行。 一些人试图直接使用futex系统调用

来实现进程同步,并寄希望获得 futex 的性能优势,这是有问题的。应该区分 futex 同步机制和 futex 系统调用。futex 同步机制还包括用户态下的操作,我们将在下节提到。

三、Futex 同步机制

所有的 futex 同步操作都应该从用户空间开始,首先创建一个 futex 同步变量,也就是位于共享内存的一个整型计数器。

当进程尝试持有锁或者要进入互斥区的时候,对 futex 执行"down"操作,即原子性的给 futex 同步变量减 1。如果同步变量变为 0,则没有竞争发生, 进程照常执行。如果同步变量是个负数,则意味着有竞争发生,需要调用 futex 系统调用的 futex_wait 操作休眠当前进程。

当进程释放锁或者要离开互斥区的时候,对 futex 进行"up"操作,即原子性的给 futex 同步变量加 1 。如果同步变量由 0 变成 1 ,则没有竞争发生,进程照常执行。如果加之前同步变量是负数,则意味着有竞争发生,需要调用 futex 系统调用的 futex_wake 操作唤醒一个或者多个等待进程。

这里的原子性加减通常是用 CAS(Compare and Swap)完成的,与平台相关。CAS的基本形式是:CAS(addr、old、new),当 addr 中存放的值等于 old 时,用 new 对其替换。在 x86 平台上有专门的一条指令来完成它:cmpxchg 。

可见:futex 是从用户态开始,由用户态和核心态协调完成的。

四、进 / 线程利用 futex 同步

进程或者线程都可以利用 futex 来进行同步。

对于线程,情况比较简单,因为线程共享虚拟内存空间,虚拟地址就可以唯一的标识出 futex 变量,即线程用同样的虚拟地址来访问 futex 变量。

对于进程,情况相对复杂,因为进程有独立的虚拟内存空间,只有通过 mmap() 让它们共享一段地址空间来使用 futex 变量。每个进程用来访问 futex 的 虚拟地址可以是不一样的,只要系统知道所有的这些虚拟地址都映射到同一个物理内存地址,并用物理内存地址来唯一标识 futex 变量。

五、小结 Futex 变量的特征:1)位于共享的用户空间中;2)是一个32位的整型;3)对它的操作是原子的。Futex 在程序 low-contention 的时候能获得比传统同步机制更好的性能。不要直接使用 Futex 系统调用。Futex 同步机制可以用于进程间同步,也可以用于线程间同步。

关于 Futex 部分转载于:https://www.cnblogs.com/ck1020/p/6666298.html

(SAW:Game Over!)
 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。