Mutex内核同步机制详解

2023-10-29

一、Mutex锁简介

在linux内核中,互斥量(mutex,即mutual exclusion)是一种保证串行化的睡眠锁机制。和spinlock的语义类似,都是允许一个执行线索进入临界区,不同的是当无法获得锁的时候,spinlock原地自旋,而mutex则是选择挂起当前线程,进入阻塞状态。正因为如此,mutex无法在中断上下文使用。和mutex更类似的机制(无法获得锁时都会阻塞)是binary semaphores,当然,mutex有更严格的使用规则:

1、只有mutex的owner可以才可以释放锁

2、不可以多次释放同一把锁

3、不允许重复获取同一把锁,否则会死锁

4、必须使用mutex初始化API来完成锁的初始化,不能使用类似memset或者memcp之类的函数进行mutex初始化

5、不可以多次重复对mutex锁进行初始化

6、线程退出后必须释放自己持有的所有mutex锁

当配置了DEBUG_MUTEXES的时候,内核会对上面的规则进行检查,防止用户误用mutex,产生各种问题。

下面是一个简单的mutex工作原理图:

6f62aa51a672e04da47f2d435e337090.png

传统的mutex只需要一个状态标记和一个等待队列就OK了,等待队列中是一个个阻塞的线程,thread owner当前持有mutex,当它离开临界区释放锁的时候,会唤醒等待队列中第一个线程(top waiter),这时候top waiter会去竞争持锁,如果成功,那么从等待队列中摘下,成为owner。如果失败,继续保持阻塞状态,等待owner释放锁的时候唤醒它。在owner task持锁过程中,如果有新的任务来竞争mutex,那么就会进入阻塞状态并插入等待队列的尾部。

相对于传统的mutex,linux内核进行了一些乐观自旋的优化,也就是说当线程持锁失败的时候,可以选择在mutex状态标记上自旋,等待owner释放锁,也可以选择进入阻塞状态并挂入等待队列。具体如何选择是在自旋等待的时间开销和进程上下文切换的开销之间进行平衡。此外为了防止多个线程自旋带来的性能问题,mutex的乐观自旋机制还引入了MCS锁,后面章节我们会详细描述。

二、数据结构

1、互斥量对象

互斥量对象用struct mutex来抽象,其成员描述如下:

42d700d51455c54b210de8e96e818b3e.png

5ab1ade8d3e5e6ca9b3c6a66166daf46.png

大部分的成员都非常好理解,除了osq这个成员,其工作原理示意图如下:

3c3d7bda3cbd6b720be629dbe1466577.png

字如其名,Optimistic spin queue就是乐观自旋队列的意思,也就是形成一组处于自旋状态的任务队列。和等待队列不一样,这个队列中的任务都是当前正在执行的任务。Osq并没有直接将这些任务的task struct形成队列结构,而是把per-CPU的mcs lock对象串联形成队列。Mcs lock中有cpu number,通过这些cpu number可以定位到指定cpu上的current thread,也就定位到了自旋的任务。

虽然都是自旋,但是自旋方式并不一样。Osq队列中的头部节点是持有osq锁的,只有该任务处于对mutex的owner进行乐观自旋的状态(我们称之mutex乐观自旋)。Osq队列中的其他节点都是自旋在自己的mcs lock上(我们称之mcs乐观自旋)。当头部的mcs lock释放掉后(结束mutex乐观自旋,持有了mutex锁),它会将mcs lock传递给下一个节点,从而让spinner队列上的任务一个个的按顺序进入mutex的乐观自旋,从而避免了cache-line bouncing带来的性能开销。

2、等待任务对象

由于是sleep lock,我们需要把等待的任务挂入队列。在内核中,Struct mutex_waiter用来抽象等待mutex的任务,其成员描述如下:

d2ef2d52468a5b9c2310c8c2e93e29ac.png

3、MCS锁对象

在linux内核中,我们对睡眠锁(例如mutex、rwsem)进行了乐观自旋的优化,这涉及到MCS lock,struct optimistic_spin_node用来抽象乐观自旋的MCS lock,其成员描述如下:

b222ecf8fecf5882aacb963ea9c0c8bb.png

三、外部接口

Mutex模块的外部接口API如下:

e072d186266b3ba1214b3f3cb466650c.png

7c051b2471350e3c1b547d33962fe758.png

四、尝试获取锁

和mutex_lock不一样,mutex_trylock只是尝试获取锁,如果成功,那么自然是好的,直接返回true,如果失败,也不会阻塞,只是返回false就可以了。代码主逻辑在__mutex_trylock_or_owner函数中,如下:

6c09899eeb5dd513b8754921f6548dba.png

A、对于mutex的owner成员,它是一个原子变量,我们采用了大量的原子操作来访问或者更新它。然而判断持锁需要一连串的操作,我们并没有采用同步机制(例如自旋锁)来保护这一段的对owner成员操作,因此,我们这些操作放到一个for循环中,在操作的结尾处会判断是否有其他线程插入修改了owner成员,如果中间有其他线程插入,那么就需要重新来过。

B、如果task非空(task变量保存了owner中去掉flag部分的任务指针),并且也不等于current thread,那么说明mutex锁被其他线程持有,还没有释放锁(也有可能在是否锁的时候,把锁直接转交给了其他线程),因此直接break跳出循环,持锁失败。

C、如果task等于current thread,而且设置了MUTEX_FLAG_PICKUP的标记,那么说明持锁线程已经把该mutex锁转交给了本线程,等待本线程来拾取。如果没有MUTEX_FLAG_PICKUP标记,那么也是直接break跳出循环,递归持锁失败。

D、有两种情况会走到这里的时候,一种情况是task为空,说明该mutex锁处于unlocked状态。另外一种情况是task非空,等于current thread,并且mutex发生了handoff,该锁被转交给当前试图持锁的线程。无论哪种情况,都可以去执行持锁操作了。

E、调用atomic_long_cmpxchg_acquire尝试获取锁,如果成功获取了锁(没有其他线程插入修改owner这个原子变量),返回NULL。如果owner发生了变化,说明中间有其他线程插入,那么重新来过。

五、获取mutex锁

mutex_lock代码如下:

3b48433bb711e40078005ab81bb3f8de.png

这里的might_sleep说明调用mutex_lock函数有可能会因为未能获取到mutex锁而进入阻塞状态。在原子上下文中(中断上下文、软中断上下文、持有自旋锁、禁止抢占等),我们不能调用可以引起阻塞的函数,因此在might_sleep函数中嵌入了这个检查,当原子上下文中调用mutex_lock函数的时候,内核会打印出内核栈的信息,从而定位这个异常。

当然,这个功能是在设置CONFIG_DEBUG_ATOMIC_SLEEP选项的情况下才生效的,如果没有设置这个选项,might_sleep函数退化为might_resched函数。在配置了抢占式内核(CONFIG_PREEMPT)或者非抢占式内核(CONFIG_PREEMPT_NONE)的情况下,might_resched是空函数。

在配置了主动抢占式内核(CONFIG_PREEMPT_VOLUNTARY)的情况下,might_resched会调用_cond_resched函数来主动触发一次抢占。

主动抢占式内核通过在might_sleep函数中增加了潜在的调度点实现了比非抢占式内核更好的延迟特性,同时确保抢占带来的进程切换开销低于抢占式内核。

Mutex是一种睡眠锁,如果未能获取锁,那么当前线程会阻塞。不过也许我们试图获取的mutex还处于空闲状态,因此通过__mutex_trylock_fast来尝试获取mutex(mutex_lock的快速路径):

de6650c4e153c40437cbc123cb9683e3.png

atomic_long_try_cmpxchg_acquire函数有三个参数,从左到右分别是value指针,old指针和new。该函数会对比*value和*old指针中的数值,如果相等执行赋值*value=new同时返回true。如果不相等,不执行赋值操作,直接返回false。

如果lock->owner的值等于0(即不仅task struct地址等于0,所有的flag也要等于0),那么将当前线程的task struct的指针赋值给lock->owner,表示该mutex锁已经被当前线程持有。如果lock->owner的值不等于0,表示该mutex锁已经被其他线程持有或者锁正在传递给top waiter线程,当前线程需要阻塞等待。需要特别说明的是上面描述的操作(比较和赋值)都是原子操作,不能有任何指令插入其中。

在未能获取mutex锁的情况下,我们需要调用__mutex_lock_slowpath函数进入慢速路径。由于会进入睡眠,因此这里需要明确当前线程需要处于的阻塞状态,主要有三种状态:D状态、S状态和KILLABLE。

当调用不同的持锁API的时候,当前线程可以处于各种不同的状态。

对于mutex_lock(大部分场景)当前线程会进入D状态。主要的代码逻辑在__mutex_lock_common函数中,我们分段解读(省略wait/wound和调试部分的代码):

b7544dbf2576c577c5748a2673dcf774.png

2dcecfe25a0e746440225f082098daa6.png

__mutex_trylock用来再次尝试获取锁,mutex_optimistic_spin则是mutex乐观自旋(Optimistic spinning)部分的代码。这两个操作只要有其一能成功获取mutex锁,那么就直接返回了。由于没有进入阻塞状态,因此这个路径也叫做中速路径。

__mutex_trylock在上一节已经讲解了,不再赘述。乐观自旋的思路是因为mutex锁可能是被其他CPU上正在执行中的线程持有,如果临界区比较短,那么有可能该mutex锁很快就被释放。这时候,与其进行一次上下文切换,还不如自旋等待,毕竟上下文切换的开销也是不小的。乐观自旋机制底层使用的是MCS锁,具体的细节我们会在其他文档中描述。

慢速路径的代码如下(省略部分代码):

9f30966ab65eb94eba155b9f9a2cdc1d.png

A、所谓慢速路径其实就是阻塞当前线程,这里将current task挂入mutex的等待队列的尾部。这样的操作让所有等待mutex的任务按照时间的先后顺序排列起来,当mutex被释放的时候,会首先唤醒队首的任务,即最先等待的任务最先被唤醒。此外,在向空队列插入第一个任务的时候,会给mutex flag设置上MUTEX_FLAG_WAITERS标记,表示已经有任务在等待这个mutex锁了。

B、进入阻塞状态,触发一次调度。由于目前执行上下文处于关闭抢占状态,因此这里的调度使用了关闭抢占版本的schedule函数。

C、该任务被唤醒之后,如果是等待队列中的第一个任务,即top waiter,那么需要给该mutex设置MUTEX_FLAG_HANDOFF,这样即便本次唤醒后无法获取到mutex(有些在该mutex上乐观自旋的任务可能会抢先获得锁),那么下一次owner释放锁的时候,看到这个handoff标记也会进行锁的交接,不再是大家抢来抢去。通过这个机制,我们可以防止spinner队列中的任务抢占CPU资源,饿死waiter队列中的任务。

D、如果获取到mutex,那么就退出循环,否则继续进入阻塞状态等待。如果是队列中的第一个waiter,那么如果__mutex_trylock失败,那么就进入乐观自旋过程,这样会有更大的机会成功获取mutex锁。

六、乐观自旋

Mutex乐观自旋的代码位于mutex_optimistic_spin函数中,进入乐观自旋函数的线程可能有下面几个结果:

1、成功获取osq锁,进入mutex乐观自旋状态,当owner释放mutex锁后,该线程结束乐观自旋,成功持有了mutex,返回true

2、未能获取osq锁,在自己的MCS锁上乐观自旋。一旦成功持锁,同步骤1

3、在MCS锁或者mcs锁乐观自旋的时候,由于各种原因(例如owner进入阻塞状态)而无法继续乐观自旋,那么mutex_optimistic_spin函数返回false,告知调用者乐观自旋失败,进入等待队列。

我们分两段来解析。首先来看第一段:

040e415848cb52daaad1181285b7bb30.png

调用mutex_optimistic_spin函数的场景有两个,一个是waiter等于NULL,这是发生在mutex_lock的早期,这时候试图持锁的线程还没有挂入等待队列,因此waiter等于NULL。另外一个场景是持锁未果,挂入等待队列,然后被唤醒之后的乐观自旋。这时候试图持锁的线程已经挂入等待队列,因此waiter非空。在这种场景下,刚唤醒的top waiter线程会给与优待,因此不需要持有osq锁就可以长驱直入,进入乐观自旋。

A、当waiter为空时,因为是正常路径的持锁请求,所以在乐观自旋之前需要持有osq锁,只有获得了osq锁,当前线程才能进入mutex乐观自旋的过程。否则只能是在自己的MCS锁上自旋等待。

B、是否乐观自旋等待mutex可以从两个视角思考:一方面,如果本cpu已经设置了need resched标记,那说明有其他任务想要抢占当前试图持锁的任务。那么current task何必乐观自旋呢,赶紧的去sleep为其他任务让路吧。另外一方面需要从owner的行为来判断。如果owner正在其他cpu欢畅运行,那么可以考虑进入乐观自旋过程。

C、在基于共享内存的多核计算系统中,mutex的实现是通过一个共享变量(owner成员)和一个队列来完成复杂的控制的。如果有多个cpu上的线程同时乐观自旋在这个共享变量上,那么就会出现缓存踩踏现象。为了解决这个问题,我们控制不能让太多的线程进入mutex乐观自旋状态(轮询owner成员),只有那些获取了osq锁的线程才能进入。未能持osq锁的线程会进入mcs锁的乐观自旋过程,等待osq锁的owner(当前在mutex乐观自旋)释放osq锁。关于osq锁的细节我们在其他文章中描述。

完成了持osq锁之后(或者是被唤醒的top waiter线程,它会掠过osq持锁过程),我们就可以进入mutex乐观自旋了,代码如下:

0d0dc3ccba5d1c0f21adeb853bd26e0a.png

A、首先还是调用__mutex_trylock_or_owner试图获取mutex锁,如果返回的owner非空(需要注意的是:这里的owner变量不包括mutex flag部分),那么说明mutex锁还在owner task手中。如果owner是空指针,说明原来持有锁的owner已经释放锁,同时这也就说明当前线程持锁成功,因此退出乐观自旋的循环。需要注意的是在退出mutex乐观自旋后会释放osq锁,从而会让spinner队列中的下一个mcs锁自旋的任务进入mutex乐观自旋状态。

B、如果__mutex_trylock_or_owner返回了非空owner,说明当前线程获取锁失败,那么可以进入mutex乐观自旋了。所谓自旋不是自旋在spinlock上,而是不断的循环检测锁的owner task是否发生变化以及owner task的运行状态。如果owner阻塞了或者当前cpu有resched的需求(可能唤醒更高级任务),那么就停止自旋,返回false,走入fail_unlock流程。

C、如果mutex锁的owner task发生变化(例如变成NULL)则mutex_spin_on_owner函数返回true,则说明可以跳转到for循环处再次尝试获取锁并进行乐观自旋。

七、释放mutex锁

mutex_unlock的代码如下:

36f2eb58df8e2997fe771837fa7a0678.png

如果一个线程获取了某个mutex锁之后,没有任何其他的线程试图进入临界区,那么这时候mutex的owner成员就是该线程的task struct地址,并且所有的mutex flag都是clear的。在这种情况下,将mutex的owner成员清零即可,不需要额外的操作,我们称之解锁快速路径(__mutex_unlock_fast)。

当然,如果有其他线程在竞争该mutex锁,那么情况会更复杂一些,这时候我们进入慢速路径(_mutex_unlock_slowpath),慢速路径的逻辑分成两段:一段是释放mutex锁,另外一段是唤醒top waiter线程。我们首先一起看第一段的代码,如下:

b244897392b2f5cf85961423577e714d.png

A、如果mutex flag中设定了handoff标记,那么说明owner在释放锁的时候要主动的把锁的owner传递给top waiter,不能让后来插入的乐观自旋的线程饿死top waiter。因此这时候我们还不能放锁,需要在__mutex_handoff函数中释放锁给top waiter。

B、将owner的task struct地址部分清掉,这也就是意味着owner task放弃了持锁。这时候,如果有乐观自旋的任务在轮询mutex owner,那么它会立刻感知到锁被释放,因此可以立刻获取mutex锁。在这样的情况下,即便后面唤醒了top waiter,但为时已晚。

C、如果等待队列中有任务阻塞在这个mutex中,那么退出循环,执行慢速路径中的第二段唤醒逻辑,否则直接返回,无需唤醒其他线程。

D、在操作owner的过程中,如果有其他线程对owner进行的修改(没有同步机制保证多线程对owner的并发操作),那么重新设定owner,再次进行检测。

第二段唤醒top waiter的代码如下:

1c36e94b30ae1d2018d8aeaa379e1e0a.png

A、代码执行至此,需要唤醒top waiter,或者处理将锁转交top waiter的逻辑,无论哪种情况,都需要从等待队列中找到top waiter。找到后将其加入wake queue。

B、如果有任务(一般是top waiter,参考其唤醒后的代码逻辑)请求handoff mutex,那么调用__mutex_handoff函数可以直接将owner设置为top waiter任务,然后该任务在醒来之后直接pickup即可。这相当与给了top waiter一些特权,防止由于不断的插入乐观自旋的任务而导致无法获取CPU资源。

C、唤醒top waiter任务

八、结论

本文简单的介绍了linux内核中的mutex同步机制,在移动环境中,mutex锁的性能表现不尽如人意,无论是吞吐量还是延迟。在重载的场景下,我们经常会遇到Ux线程阻塞在mutex而引起的手机卡顿问题,如何在手机平台上优化mutex锁的性能是我们OPPO内核团队一直在做的事情,也欢迎热爱技术的你积极参与。

参考文献:

1、内核源代码

2、linux-5.10.61\Documentation\scheduler\*

3、https://zhuanlan.zhihu.com/p/364130923

df07d983512260dceea268068ca933a7.gif

长按关注内核工匠微信


Linux 内核黑科技 | 技术文章 | 精选教程
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mutex内核同步机制详解 的相关文章

  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • 跟踪 pypi 依赖项 - 谁在使用我的包

    无论如何 是否可以通过 pip 或 PyPi 来识别哪些项目 在 Pypi 上发布 可能正在使用我的包 也在 PyPi 上发布 我想确定每个包的用户群以及可能尝试积极与他们互动 预先感谢您的任何答案 即使我想做的事情是不可能的 这实际上是不
  • 使用 kivy textinput 的 'input_type' 属性的问题

    您好 我在使用 kivy 的文本输入小部件的 input type 属性时遇到问题 问题是我制作了两个自定义文本输入 其中一个称为 StrText 其中设置了 input type text 然后是第二个文本输入 名为 NumText 其
  • Android 时钟滴答数 [赫兹]

    关于 proc pid stat 中应用程序的总 CPU 使用率 https stackoverflow com questions 16726779 total cpu usage of an application from proc
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • 如何使用 Pandas、Numpy 加速 Python 中的嵌套 for 循环逻辑?

    我想检查一下表的字段是否TestProject包含了Client端传入的参数 嵌套for循环很丑陋 有什么高效简单的方法来实现吗 非常感谢您的任何建议 def test parameter a list parameter b list g
  • Python 2:SMTPServerDisconnected:连接意外关闭

    我在用 Python 发送电子邮件时遇到一个小问题 me my email address you recipient s email address me email protected cdn cgi l email protectio
  • nslookup 报告“无法解析 '(null)': 名称无法解析”,尽管它成功解析了 DNS 名称

    我在 ubuntu 上 并且正在运行 docker 默认桥接网络 我有 Zookeeper kafka 的容器化版本 以及我编写的与 kafka 对话的应用程序 I do a docker exec it
  • “隐藏”内置类对象、函数、代码等的名称和性质[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我很好奇模块中存在的类builtins无法直接访问的 例如 type lambda 0 name function of module
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • 不同编程语言中的浮点数学

    我知道浮点数学充其量可能是丑陋的 但我想知道是否有人可以解释以下怪癖 在大多数编程语言中 我测试了 0 4 到 0 2 的加法会产生轻微的错误 而 0 4 0 1 0 1 则不会产生错误 两者计算不平等的原因是什么 在各自的编程语言中可以采
  • 使用特定颜色和抖动在箱形图上绘制数据点

    我有一个plotly graph objects Box图 我显示了箱形 图中的所有点 我需要根据数据的属性为标记着色 如下所示 我还想抖动这些点 下面未显示 Using Box我可以绘制点并抖动它们 但我不认为我可以给它们着色 fig a
  • 如何在 pygtk 中创建新信号

    我创建了一个 python 对象 但我想在它上面发送信号 我让它继承自 gobject GObject 但似乎没有任何方法可以在我的对象上创建新信号 您还可以在类定义中定义信号 class MyGObjectClass gobject GO
  • 在本地网络上运行 Bokeh 服务器

    我有一个简单的 Bokeh 应用程序 名为app py如下 contents of app py from bokeh client import push session from bokeh embed import server do
  • Python ImportError:无法导入名称 __init__.py

    我收到此错误 ImportError cannot import name life table from cdc life tables C Users tony OneDrive Documents Retirement retirem
  • 实现 XGboost 自定义目标函数

    我正在尝试使用 XGboost 实现自定义目标函数 在 R 中 但我也使用 python 所以有关 python 的任何反馈也很好 我创建了一个返回梯度和粗麻布的函数 它工作正常 但是当我尝试运行 xgb train 时它不起作用 然后 我
  • 使用for循环时如何获取前一个元素? [复制]

    这个问题在这里已经有答案了 可能的重复 Python 循环内的上一个和下一个值 https stackoverflow com questions 1011938 python previous and next values inside
  • 在 JavaScript 函数的 Django 模板中转义字符串参数

    我有一个 JavaScript 函数 它返回一组对象 return Func id name 例如 我在传递包含引号的字符串时遇到问题 Dr Seuss ABC BOOk 是无效语法 I tried name safe 但无济于事 有什么解
  • 更改 Tk 标签小部件中单个单词的颜色

    我想更改 Tkinter 标签小部件中单个单词的字体颜色 我知道可以使用文本小部件来实现与我想要完成的类似的事情 例如使单词 YELLOW 显示为黄色 self text tag config tag yel fg clr yellow s
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两

随机推荐

  • python echarts mysql_利用ECharts可视化mysql数据库中的数据

    这是工程所有文件的一个目录 工程文件目录 我做了一个柱状图 一个饼状图 一个折线图 配置过程很恶心 出了好多错 所以在这里记录一下 如果想直接看 echarts 的部分 可以跳过下面数据库的建立 数据库的建立与获取数据 首先是建立数据库 数
  • 科技查新-委托书

    查新检索委托书要怎么填 什么时候需要填写查新检索委托书 委托查新机构做科技查新时 根据参考项目的专业特点 委托人需选择具备相应资质的查新机构 委托可以通过网上或现场提交委托书 并按照要求填写查新检索委托书 查新检索委托书需要填写哪些内容 在
  • 产品经理使用工具-----产品演示 Demo-builder

    Demo Builder 提供了一种简单的方法来创建显示软件和系统是如何工作的教程 演示或示范 Demo Builder 的易用性使您能够创建令人惊叹 但实际与专业教学视频的功能 Demo Builder 用于生成你需要教育 市场 或出售该
  • 编译型与解释型、动态语言与静态语言、强类型语言与弱类型语言的区别

    编译型和解释型 我们先看看编译型 其实它和汇编语言是一样的 也是有一个负责翻译的程序来对我们的源代码进行转换 生成相对应的可执行代码 这个过程说得专业一点 就称为编译 Compile 而负责编译的程序自然就称为编译器 Compiler 如果
  • Python day04 作业

    数学方面 五角星 一个五角星被定义为n 3n 1 2 def getPentagalNumber n c n 3 n 1 2 if n 10 0 print c end else print for i in range 1 101 get
  • Ubuntu在安装snappy时出现CMake Error at CMakeLists.txt:300 (set_property): set_property could not find TA

    在Ubuntu安装snappy过程中 出现了如下问题提示 这个要怎么解决 求各位大神解答 CMake Error at CMakeLists txt 294 add subdirectory The source directory hom
  • 华为OD机试 - 计算礼品发放的最小分组数目(Java)

    题目描述 又到了一年的末尾 项目组让小明负责新年晚会的小礼品发放工作 为使得参加晚会的同事所获得的小礼品价值相对平衡 需要把小礼品根据价格进行分组 但每组最多只能包括两件小礼品 并且每个分组的价格总和不能超过一个价格上限 为了保证发放小礼品
  • 小试牛刀1:使用Python-OpenCV 实现一副图片的高斯模糊处理

    实验步骤 1 环境 安装好python3 x opencv3 3 window下 2 高斯模糊 概念 高斯模糊本质上是低通滤波器 输出图像的每个像素点是原图像上对应像素点与周围像素点的加权和 使用cv2做高斯模糊 只要一行代码调用Gauss
  • 微信小程序页面栈_小程序页面栈详解

    在做小程序项目的时候不难发现 使用navigateTo进行页面跳转后 点击左上角或使用navigateBack返回 总是会按照之前的页面进入倒序来展示页面 那么问题来了 它们的跳转规则是什么样的呢 结合到实际业务中如何灵活运用呢 什么是页面
  • No SOURCES given to target: xxx

    文章目录 一 问题描述 二 解决办法 一 问题描述 CMake Error at CMakeLists txt add executable Cannot find source file src rs capture cpp Tried
  • 关于搭建简易广域网私人通信程序(python)一步到位!

    原料 python3 腾讯云服务器 用到的库 socket sys threading time pyinstaller 除pyinstaller外均不需单独安装 首先 默认已经买好云服务器 且安装好了python3 此处使用腾讯云服务器
  • csv文件的读与写

    csv文件的读取与写入 1 csv文件的读取 import pandas as pd csv path dataA1 csv df pd read csv csv path 可以通过csv文件的表头读取出某一列 表头见下图 print it
  • 理解inode

    inode是一个重要概念 是理解Unix Linux文件系统和硬盘储存的基础 我觉得 理解inode 不仅有助于提高系统操作水平 还有助于体会Unix设计哲学 即如何把底层的复杂性抽象成一个简单概念 从而大大简化用户接口 下面就是我的ino
  • 华为OD机试真题-基站维护最短距离 【2023.Q1】

    参考代码 小王是一名基站维护工程师 负责某区域的基站维护 某地方有n个基站 1
  • Android中的签名和签名文件的生成过程

    一 概述 二 还是从Key Store和keytool说起吧 三 数字签名和数字证书 四 apk的签名过程 五 签名中 MANIFEST MF CERT SF和 CERT RSA是怎么生成的 1 MANIFEST MF 2 CERT SF
  • QT日志系统创建,读取,修复

    一 内容简介 构建QT日志系统 遇到的问题以及结局办法 读取日志文件 用于检查程序运行情况 并且修复异常数据 二 软件环境 2 1 QT 5 14 1 新版QT6 4 6 5在线安装经常失败 而5 9版本又无法编译64位程序 所以就采用5
  • 巧用千寻位置GNSS软件

    千寻位置GNSS软件中的CAD功能 用于已有 CAD的图形的导入和编辑 并且可以对 CAD图形已有线条进行线放样 在日常测绘工作中十分常见 下面向各位介绍CAD功能的使用技巧 点击 测量 gt CAD 进入 CAD功能如图 5 3 1所示
  • 显卡无法为此计算机,如何解决win10系统电脑中无法安装intel显卡驱动的问题

    如何解决win10系统电脑中无法安装intel显卡驱动的问题 腾讯视频 爱奇艺 优酷 外卖 充值4折起 在使用win10系统电脑的时候 如果我们想要安装intel显卡驱动 却提示无法安装的话 应如何处理呢 接下来就由小编来告诉大家 一 手动
  • CentOS7(Linux)安装总结

    主要参考以下文章 CentOS7 Linux 详细安装教程 图文详解 缄默 給 傷的博客 CSDN博客 linuxcentos7安装步骤https blog csdn net weixin 43849575 article details
  • Mutex内核同步机制详解

    一 Mutex锁简介 在linux内核中 互斥量 mutex 即mutual exclusion 是一种保证串行化的睡眠锁机制 和spinlock的语义类似 都是允许一个执行线索进入临界区 不同的是当无法获得锁的时候 spinlock原地自