自旋锁和互斥锁的区别

2023-05-16

 面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

 

百度安全验证

自旋锁和互斥锁的区别_一缕阳光a的博客-CSDN博客_自旋锁和互斥锁的区别

POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套API。

线程同步是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间的共享临界区(Critical Section)进行保护(另一种常用的同步机制是barrier)。

Pthreads提供了多种锁机制:

  • Mutex(互斥量):pthread_mutex_t
  • Spin lock(自旋锁): pthread_spin_t
  • Condition Variable(条件变量): pthread_cond_t
  • Read/Write lock(读写锁):pthread_rwlock_t

Pthreads提供的Mutex锁操作相关的API主要有:

  • pthread_mutex_lock(pthread_mutex_t *mutex);
  • pthread_mutex_trylock(pthread_mutex_t *mutex);
  • pthread_mutex_unlock(pthread_mutex_t *mutex);

Pthreads提供的Spin Lock锁操作相关的API主要有:

  • pthread_spin_lock(pthread_spinlock_t *lock);
  • pthread_spin_trylock(pthread_spinlock_t *lock);
  • pthread_spin_unlock(pthread_spinlock_t *lock);

从实现原理上来讲,Mutex(互斥锁)属于sleep-waiting类型的锁

例如:在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞,

Core0会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其它的任务而不必进行忙等待。

Spin lock(自旋锁)则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。

自旋锁(Spin lock)

自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,

“自旋锁”的作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远高于互斥锁。

自旋锁的不足之处:

自旋锁一直占用着CPU,他在未获得锁的情况下,一直运行(自旋),所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低。

在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。

因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式SMP的情况下才真正需要

在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。

自旋锁适用于锁使用者保持锁时间比较短的情况下。

自旋锁-原理

跟互斥锁一样,一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁,在访问完共享资源后,必须释放锁如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。由此我们可以看出,自旋锁是一种比较低级的保护数据结构或代码片段的原始方式,这种锁可能存在两个问题:

1、死锁。试图递归地获得自旋锁必然会引起死锁:递归程序的持有实例在第二个实例循环,以试图获得相同自旋锁时,不会释放此自旋锁。

在递归程序中使用自旋锁应遵守下列策略:

递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂"自旋",也无法获得资源,从而进入死循环。

2、过多占用cpu资源。如果不加限制,由于申请者一直在循环等待,因此自旋锁在锁定的时候,如果不成功,不会睡眠,会持续的尝试,单cpu的时候自旋锁会让其它process动不了. 因此,一般自旋锁实现会有一个参数限定最多持续尝试次数. 超出后, 自旋锁放弃当前time slice. 等下一次机会

由此可见,自旋锁比较适用于锁使用者保持锁时间比较短的情况。正是由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作,

总结:

互斥锁与自旋锁的区别

(1)、互斥锁mutex:独占锁;开销大

pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_unlock(pthread_mutex_t *mutex);

(2)、自旋锁spin lock:轻量级的锁,开销小;适用于短时间内对锁的使用。

如果自旋锁已经被其他的执行单元保持,调用者就一直循环在那里判断该自旋锁是否被释放

pthread_spin_lock(pthread_spinlock_t *lock);

pthread_spin_unlock(pthread_spinlock_t *lock);

注意:对于自旋锁spin lock,如果递归调用过深,会导致死锁。

面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

前言

生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来、电动车被偷等等。

但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就可以轻轻松松地把你电动车给「顺走」,不然打工怎么会是他这辈子不可能的事情呢?牛逼之人,必有牛逼之处。

那在编程世界里,「锁」更是五花八门,多种多样,每种锁的加锁开销以及应用场景也可能会不同。

如何用好锁,也是程序员的基本素养之一了。

高并发的场景下,如果选对了合适的锁,则会大大提高系统的性能,否则性能会降低。

所以,知道各种锁的开销,以及应用场景是很有必要的。

接下来,就谈一谈常见的这几种锁:

多线程访问共享资源的时候,避免不了资源竞争而导致数据错乱的问题,所以我们通常为了解决这一问题,都会在访问共享资源之前加锁。

最常用的就是互斥锁,当然还有很多种不同的锁,比如自旋锁、读写锁、乐观锁等,不同种类的锁自然适用于不同的场景。

如果选择了错误的锁,那么在一些高并发的场景下,可能会降低系统的性能,这样用户体验就会非常差了。

所以,为了选择合适的锁,我们不仅需要清楚知道加锁的成本开销有多大,还需要分析业务场景中访问的共享资源的方式,再来还要考虑并发访问共享资源时的冲突概率。

对症下药,才能减少锁对高并发性能的影响。

那接下来,针对不同的应用场景,谈一谈「互斥锁、自旋锁、读写锁、乐观锁、悲观锁」的选择和使用。

前言互斥锁与自旋锁:谁更轻松自如?

最底层的两种就是会「互斥锁和自旋锁」,有很多高级的锁都是基于它们实现的,你可以认为它们是各种锁的地基,所以我们必须清楚它俩之间的区别和应用。

加锁的目的就是保证共享资源在任意时间里,只有一个线程访问,这样就可以避免多线程导致共享数据错乱的问题。

当已经有一个线程加锁后,其他线程加锁则就会失败,互斥锁和自旋锁对于加锁失败后的处理方式是不一样的:

互斥锁加锁失败后,线程会释放 CPU ,给其他线程;自旋锁加锁失败后,线程会忙等待,直到它拿到锁;互斥锁是一种「独占锁」,比如当线程 A 加锁成功后,此时互斥锁已经被线程 A 独占了,只要线程 A 没有释放手中的锁,线程 B 加锁就会失败,于是就会释放 CPU 让给其他线程,既然线程 B 释放掉了 CPU,自然线程 B 加锁的代码就会被阻塞。

对于互斥锁加锁失败而阻塞的现象,是由操作系统内核实现的。当加锁失败时,内核会将线程置为「睡眠」状态,等到锁被释放后,内核会在合适的时机唤醒线程,当这个线程成功获取到锁后,于是就可以继续执行。如下图:

所以,互斥锁加锁失败时,会从用户态陷入到内核态,让内核帮我们切换线程,虽然简化了使用锁的难度,但是存在一定的性能开销成本。

那这个开销成本是什么呢?会有两次线程上下文切换的成本:

当线程加锁失败时,内核会把线程的状态从「运行」状态设置为「睡眠」状态,然后把 CPU 切换给其他线程运行;接着,当锁被释放时,之前「睡眠」状态的线程会变为「就绪」状态,然后内核会在合适的时间,把 CPU 切换给该线程运行。线程的上下文切换的是什么?当两个线程是属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。

上下切换的耗时有大佬统计过,大概在几十纳秒到几微秒之间,如果你锁住的代码执行时间比较短,那可能上下文切换的时间都比你锁住的代码执行时间还要长。

所以,如果你能确定被锁住的代码执行时间很短,就不应该用互斥锁,而应该选用自旋锁,否则使用互斥锁。

自旋锁是通过 CPU 提供的 CAS 函数(Compare And Swap),在「用户态」完成加锁和解锁操作,不会主动产生线程上下文切换,所以相比互斥锁来说,会快一些,开销也小一些。

一般加锁的过程,包含两个步骤:

第一步,查看锁的状态,如果锁是空闲的,则执行第二步;第二步,将锁设置为当前线程持有;CAS 函数就把这两个步骤合并成一条硬件级指令,形成原子指令,这样就保证了这两个步骤是不可分割的,要么一次性执行完两个步骤,要么两个步骤都不执行。

使用自旋锁的时候,当发生多线程竞争锁的情况,加锁失败的线程会「忙等待」,直到它拿到锁。这里的「忙等待」可以用 while 循环等待实现,不过最好是使用 CPU 提供的 PAUSE 指令来实现「忙等待」,因为可以减少循环等待时的耗电量。

自旋锁是最比较简单的一种锁,一直自旋,利用 CPU 周期,直到锁可用。需要注意,在单核 CPU 上,需要抢占式的调度器(即不断通过时钟中断一个线程,运行其他线程)。否则,自旋锁在单 CPU 上无法使用,因为一个自旋的线程永远不会放弃 CPU。

自旋锁开销少,在多核系统下一般不会主动产生线程切换,适合异步、协程等在用户态切换请求的编程方式,但如果被锁住的代码执行时间过长,自旋的线程会长时间占用 CPU 资源,所以自旋的时间和被锁住的代码执行的时间是成「正比」的关系,我们需要清楚的知道这一点。

自旋锁与互斥锁使用层面比较相似,但实现层面上完全不同:当加锁失败时,互斥锁用「线程切换」来应对,自旋锁则用「忙等待」来应对。

它俩是锁的最基本处理方式,更高级的锁都会选择其中一个来实现,比如读写锁既可以选择互斥锁实现,也可以基于自旋锁实现。

读写锁:读和写还有优先级区分?

读写锁从字面意思我们也可以知道,它由「读锁」和「写锁」两部分构成,如果只读取共享资源用「读锁」加锁,如果要修改共享资源则用「写锁」加锁。

所以,读写锁适用于能明确区分读操作和写操作的场景。

读写锁的工作原理是:

当「写锁」没有被线程持有时,多个线程能够并发地持有读锁,这大大提高了共享资源的访问效率,因为「读锁」是用于读取共享资源的场景,所以多个线程同时持有读锁也不会破坏共享资源的数据。但是,一旦「写锁」被线程持有后,读线程的获取读锁的操作会被阻塞,而且其他写线程的获取写锁的操作也会被阻塞。所以说,写锁是独占锁,因为任何时刻只能有一个线程持有写锁,类似互斥锁和自旋锁,而读锁是共享锁,因为读锁可以被多个线程同时持有。

知道了读写锁的工作原理后,我们可以发现,读写锁在读多写少的场景,能发挥出优势。

另外,根据实现的不同,读写锁可以分为「读优先锁」和「写优先锁」。

读优先锁期望的是,读锁能被更多的线程持有,以便提高读线程的并发性,

它的工作方式是:当读线程 A 先持有了读锁,写线程 B 在获取写锁的时候,会被阻塞,并且在阻塞过程中,后续来的读线程 C 仍然可以成功获取读锁,最后直到读线程 A 和 C 释放读锁后,写线程 B 才可以成功获取读锁。如下图:

而写优先锁是优先服务写线程,其工作方式是:当读线程 A 先持有了读锁,写线程 B 在获取写锁的时候,会被阻塞,并且在阻塞过程中,后续来的读线程 C 获取读锁时会失败,于是读线程 C 将被阻塞在获取读锁的操作,这样只要读线程 A 释放读锁后,写线程 B 就可以成功获取读锁。如下图:

读优先锁对于读线程并发性更好,但也不是没有问题。我们试想一下,如果一直有读线程获取读锁,那么写线程将永远获取不到写锁,这就造成了写线程「饥饿」的现象

写优先锁可以保证写线程不会饿死,但是如果一直有写线程获取写锁,读线程也会被「饿死」。

既然不管优先读锁还是写锁,对方可能会出现饿死问题,那么我们就不偏袒任何一方,搞个「公平读写锁」。

公平读写锁比较简单的一种方式是:用队列把获取锁的线程排队,不管是写线程还是读线程都按照先进先出的原则加锁即可,这样读线程仍然可以并发,也不会出现「饥饿」的现象。

互斥锁和自旋锁都是最基本的锁,读写锁可以根据场景来选择这两种锁其中的一个进行实现。

乐观锁与悲观锁:做事的心态有何不同?

前面提到的互斥锁、自旋锁、读写锁,都是属于悲观锁

悲观锁做事比较悲观,它认为多线程同时修改共享资源的概率比较高,于是很容易出现冲突,所以访问共享资源前,先要上锁。

那相反的,如果多线程同时修改共享资源的概率比较低,就可以采用乐观锁

乐观锁做事比较乐观,它假定冲突的概率很低.

它的工作方式是:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

放弃后如何重试,这跟业务场景息息相关,虽然重试的成本很高,但是冲突的概率足够低的话,还是可以接受的。

可见,乐观锁的心态是,不管三七二十一,先改了资源再说。另外,你会发现乐观锁全程并没有加锁,所以它也叫无锁编程。

这里举一个场景例子:在线文档。

我们都知道在线文档可以同时多人编辑的,如果使用了悲观锁,那么只要有一个用户正在编辑文档,此时其他用户就无法打开相同的文档了,这用户体验当然不好了。

那实现多人同时编辑,实际上是用了乐观锁,它允许多个用户打开同一个文档进行编辑,编辑完提交之后才验证修改的内容是否有冲突。

怎么样才算发生冲突?这里举个例子,比如用户 A 先在浏览器编辑文档,之后用户 B 在浏览器也打开了相同的文档进行编辑,但是用户 B 比用户 A 提交改动,这一过程用户 A 是不知道的,当 A 提交修改完的内容时,那么 A 和 B 之间并行修改的地方就会发生冲突。

服务端要怎么验证是否冲突了呢?通常方案如下:

由于发生冲突的概率比较低,所以先让用户编辑文档,但是浏览器在下载文档时会记录下服务端返回的文档版本号;当用户提交修改时,发给服务端的请求会带上原始文档版本号,服务器收到后将它与当前版本号进行比较,如果版本号一致则修改成功,否则提交失败。实际上,我们常见的 SVN 和 Git 也是用了乐观锁的思想先让用户编辑代码,然后提交的时候,通过版本号来判断是否产生了冲突,发生了冲突的地方,需要我们自己修改后,再重新提交。

乐观锁虽然去除了加锁解锁的操作,但是一旦发生冲突,重试的成本非常高,所以只有在冲突概率非常低,且加锁成本非常高的场景时,才考虑使用乐观锁。

总结

开发过程中,最常见的就是互斥锁的了,互斥锁加锁失败时,会用「线程切换」来应对,当加锁失败的线程再次加锁成功后的这一过程,会有两次线程上下文切换的成本,性能损耗比较大。

如果我们明确知道被锁住的代码的执行时间很短,那我们应该选择开销比较小的自旋锁,因为自旋锁加锁失败时,并不会主动产生线程切换,而是一直忙等待,直到获取到锁,那么如果被锁住的代码执行时间很短,那这个忙等待的时间相对应也很短。

如果能区分读操作和写操作的场景,那读写锁就更合适了,它允许多个读线程可以同时持有读锁,提高了读的并发性。根据偏袒读方还是写方,可以分为读优先锁和写优先锁,读优先锁并发性很强,但是写线程会被饿死,而写优先锁会优先服务写线程,读线程也可能会被饿死,那为了避免饥饿的问题,于是就有了公平读写锁,它是用队列把请求锁的线程排队,并保证先入先出的原则来对线程加锁,这样便保证了某种线程不会被饿死,通用性也更好点。

互斥锁和自旋锁都是最基本的锁,读写锁可以根据场景来选择这两种锁其中的一个进行实现。

另外,互斥锁、自旋锁、读写锁都属于悲观锁,悲观锁认为并发访问共享资源时,冲突概率可能非常高,所以在访问共享资源前,都需要先加锁。

相反的,如果并发访问共享资源时,冲突概率非常低的话,就可以使用乐观锁,它的工作方式是,在访问共享资源时,不用先加锁,修改完共享资源后,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

但是,一旦冲突概率上升,就不适合使用乐观锁了,因为它解决冲突的重试成本非常高。

不管使用的哪种锁,我们的加锁的代码范围应该尽可能的小,也就是加锁的粒度要小,这样执行速度会比较快。再来,使用上了合适的锁,就会快上加快了。

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

自旋锁和互斥锁的区别 的相关文章

  • 简析车载以太网TSN标准

    众所周知 xff0c 通用以太网是以非同步方式工作的 xff0c 网络中任何设备都可以随时发送数据 xff0c 因此在数据的传输时间上既不精准也不确定 xff1b 同时 xff0c 广播数据或视频等大规模数据的传输 xff0c 也会因网络负
  • 英伟达发布的系统级芯片orin

    本文为英伟达全面分析的第七篇文章 xff0c 关注英伟达在今年会大规模交付的Orin系统级芯片 Orin 是亚特兰蒂斯神话第一任统治者 xff0c 海王Altan的儿子 Orin一经发布 xff0c 便成为众多车企争抢装车的对象 本文重点探
  • Shell内置命令之exit的语法与实例

    系统中是有exit命令的 用于退出当前用户的登录状态 但是在 Shell 脚本中 exit 语句是用来退出当前脚本的 下面这篇文章主要给大家介绍了关于Shell内置命令之exit的语法与实例 需要的朋友可以参考下 https www jb5
  • SHELL编程

    一 变量 1 shell 脚本基础知识 编译型语言 xff1a 如 c语言 解释型语言 xff1a shell 脚本 shell脚本的本质 xff1a shell命令的有序集合 2 shell 编程的基本过程 基本过程分为三步 xff1a
  • 浅谈TC8数据链路层测试

    当今时代 xff0c 智能汽车已成为一个炙手可热的话题 xff0c 各种先进汽车电子技术蓬勃发展 xff0c 比如自动驾驶 V2X OTA 这些新技术的背后都离不开车载以太网通信技术的支持 浅谈TC8数据链路层测试 知乎 其中数据链路层实现
  • 100 道 Linux 常见面试题 建议收藏,慢慢读~

    本文共 2W 43 字 xff0c 分别从 Linux 概述 磁盘 目录 文件 安全 语法级 实战 文件管理命令 文档编辑命令 磁盘管理命令 网络通讯命令 系统管理命令 备份压缩命令等方面拆解 Linux 常见面试问题 可以先收藏 xff0
  • patchelf 的功能以及使用 patchelf 修改 rpath 以解决动态库问题

    低版本 libc 库运行高版本 libc 库编译的程序 https blog csdn net Longyu wlz article details 108023117 在这篇博客中我描述了使用 patchelf 来修改动态库链接器的方法
  • Alpha-beta 算法

    Alpha beta 算法是棋类游戏中最常用的 xff0c 也是最基础的剪枝方法 xff0c 要说Alpha beta 算法 就得先说下max min博弈树 算法 xff0c 就是模拟电脑下子 xff0c 要下在对电脑最优的地方 xff0c
  • 关于SOME/IP的理解

    1 总体说明 如上图所示为标准的网络七层架构 xff0c SOME IP Scalable service Oriented MiddlewarE over IP xff0c 即 运行于IP之上的可伸缩的面向服务的中间件 他在系统中其实就是
  • Win10常用快捷键

  • 推荐3篇 如何建立自己的知识体系

    如何构建自己的知识体系 xff1f 看这一篇就够了 xff01 如何把学到的知识系统化 xff1f 怎么才能把知识系统化的学透彻呢 xff1f 这3步可以帮助你 什么是知识体系 xff1f 为什么要搭建知识体系 xff1f 如何搭建知识体系
  • 《富有的习惯》

    目录 关于作者 关于本书 核心内容 前言 第一部分 第二部分 习惯觉察表 结语 富人和穷人的区别是什么 xff1f 富人永远更谨慎 关于作者 本书作者是托马斯 科里 xff0c 他是一位美国著名的会计师和注册理财规划师 xff0c 开办了一
  • 演讲培训——荣耀时刻

    如何用惊艳的开场白引爆项目路演的全场 xff1f 如何用精准而生动的语言表达有力的商务主题 xff1f 如何层层递进环环相扣地展开内容 xff1f 如何打造激励人心激发行动的演讲结尾 xff1f 如何让观点有内在 xff0c 让语言有逻辑
  • QNX的调度算法

    作为一个硬实时操作系统 xff0c QNX是一个基于优先级抢占的系统 这也导致其基本调度算法相对比较简单 因为不需要像别的通用操作系统考虑一些复杂的 公平性 xff0c 只需要保证 优先级最高的线程最优先得到 CPU 就可以了 基本调度算法
  • 葡萄酒品酒的四个步骤

    第一步 xff1a 观色 将酒杯举到白色背景之上 xff0c 然后倾斜约45 xff0c 仔细观察酒液中心的颜色 边缘色泽 澄清度 通常而言 xff0c 红葡萄酒的越浅 xff0c 年份越老 xff1b 白葡萄酒的颜色越浅 xff0c 年份
  • 高通骁龙 8155 到底有什么魔力?

    高通骁龙8155采用安卓系统 xff0c 兼容性更好 xff0c APP的数量也就相当多 xff0c 硬件方面 xff0c 这颗芯片最高支持3个4K屏或4个2K屏 xff0c 4个麦克风6颗摄像头 xff0c 还有WiFi6 5G 蓝牙5
  • 当你遇到Bug该怎么办?

    一 问题复现 稳定复现问题才能正确的对问题进行定位 解决以及验证 一般来说 xff0c 越容易复现的问题越容易解决 1 1 模拟复现条件 有的问题存在于特定的条件下 xff0c 只需要模拟出现问题的条件即可复现 对于依赖外部输入的条件 xf
  • 增加远程访问用户

    http www zhuangjiba com hardware 34023 html http www zhuangjiba com hardware 34023 html 打开管理员权限 xff1a
  • 基于Java的“多功能五子棋”游戏的设计和实现

    源码地址 xff1a http download csdn net detail clx55555 9718406 下载或转载使用请声明原著 xff1a 但求心安 基于 Java的 多功能五子棋 游戏的设计和实现 引言 随着经济社会的迅速发

随机推荐

  • shell 脚本中的注释详解

    单行注释 xff1a 单行注释就比较简单了 xff0c 直接在行最前端加上符号 即可 具体用法如下所示 xff1a this is comment test echo 34 this is comment test 34 运行结果 xff1
  • 《演讲的本质》:如何做好一次公开演讲?

    关于本书 演讲的本质 是一本教你通过演讲最大化自己的影响力 建立信任关系的工具书 xff0c 探讨演讲的本质和价值 本书从视觉 听觉 语言三个角度来分析如何最大程度地打动听众 xff0c 并提供了行之有效的练习方法 核心内容 演讲的本质与价
  • ubuntu系统镜像下载源

    ubuntu 14 04 和16 04 快速下载 由于官网服务器在国外 xff0c 下载速度奇慢 xff0c 所以我们可以利用阿里云镜像下载ubuntu ubuntu 14 04 xff1a ubuntu releases 14 04安装包
  • 每天最重要的2小时

    关于作者 乔西 戴维斯 xff0c 他是哥伦比亚大学的心理学博士 xff0c 主要研究神经学领域 关于本书 从身体效能的角度 xff0c 让我们在面对一件事情时 xff0c 怎么才能把身体调整到一种巅峰状态 xff0c 进而对时间进行高效的
  • 【无标题】

    63张图 xff0c 一步一步带你弄清 Linux 虚拟内存管理 xff0c 厉害 内存管理子系统可谓是 Linux 内核众多子系统中最为复杂最为庞大的一个 xff0c 其中包含了众多繁杂的概念和原理 xff0c 通过内存管理这条主线我们把
  • 面试时不懂得自我介绍的人,最后都被PASS掉了

    做硬件维护的阿润最近后悔得直跳脚 在被公司赔偿清退后 xff0c 他直接开启了HIGH玩模式 xff0c 原计划先玩2个月再做面试准备 xff0c 结果冷不丁接到心仪公司的面试邀约 因为时间紧 邀约急 xff0c 在没做好充分准备的前提下
  • 开发板和电脑可以ping通但是ssh连接不上

    一 问题描述 某集群数据节点服务器频繁无法连接 xff0c 服务器间出现可ping通但ssh无法连接的情况 xff0c 使用带外地址登录后远程控制也无法显示正常界面 xff0c 重启后会短暂恢复 二 排查问题 重启服务器后检查服务器SSH状
  • 你对Linux下的实时性应该多点了解

    本文讲述一些有利于提高xenomai实时性的配置建议 xff0c 部分针对X86架构 xff0c 但它们的底层原理相通 xff0c 同样适用于其他CPU架构和系统 xff0c 希望对你有用 希望能够帮助大家 本文来自于微信公众号嵌入式Lin
  • 怎么保证ECU的“实时性”

    在最近一起有公开报道的辅助驾驶相关事故中 xff0c 由于AEB xff08 自动紧急制动系统 xff09 功能被怀疑没有起作用 xff0c 又有一家车企的高级辅助驾驶功能遭到质疑 其实 xff0c 目前大多数车辆中AEB功能的生效车速区间
  • 重磅成果丨ASAM SOVD 1.0.0正式发布

    重磅成果丨ASAM SOVD 1 0 0正式发布 测试行业动态 汽车测试网 编者寄语 xff1a 2022年6月底 xff0c ASAM SOVD 1 0 0版本正式发布 为了应对智能网联汽车时代井喷的软件诊断需求 xff0c SOVD如何
  • 2016-我在路上

    2016匆匆而过 xff0c 这一年做了很多 xff0c 也错过了很多 有些事情自己感觉很值得 xff0c 有些事情感觉很愧疚 xff0c 一年的酸甜苦辣尽在其中 寒假 xff0c 我加入的acm实验室 xff0c 有个集训 xff0c 但
  • 《复盘高手》

    今天为你介绍的是 复盘高手 xff0c 副标题是 自我认识与自我精进的底层逻辑 复盘 本是围棋的一个术语 xff0c 说的是下完一盘棋后 xff0c 棋手在棋盘上把下棋的过程复现一遍 xff0c 看看哪些地方下得好 xff0c 哪些地方不好
  • Linux 进程间通信(六)共享内存

    可以说 xff0c 共享内存是一种最为高效的进程间通信方式 xff0c 因为进程可以直接读写内存 xff0c 不需要任何数据的复制 为了在多个进程间交换信息 xff0c 内核专门留出了一块内存区 xff0c 这段内存区可以由需要访问的进程将
  • 对ASPICE的理解

    Aspice xff08 Automotive SPICE xff09 中文翻译为汽车软件过程改进及能力评定 是为保证软件质量的规范 xff0c 要求供应商按照Automotive SPICE的要求进行产品的设计与开发 是汽车行业中常用于质
  • 普通人如何改变自己的命运?

    Morty 普通人改变命运的秘密 xff01 我的观点可能会颠覆你的认知 哔哩哔哩 bilibili 非常感谢UP xff0c 你的每个视频我都看了 xff0c 给我启示最大的是 为什么你总是那么穷 xff0c 这些年一直走背运 xff0c
  • 指令流水线

    为提高处理器执行指令的效率 xff0c 把一条指令的操作分成多个细小的步骤 xff0c 每个步骤由专门的电路完成的方式 指令流水线是为提高处理器执行指令的效率 xff0c 把一条指令的操作分成多个细小的步骤 xff0c 每个步骤由专门的电路
  • 何为CPU的亲和性

    CPU的亲和性 xff0c 进程要在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性 xff0c 进程迁移的频率小就意味着产生的负载小 亲和性一词是从affinity翻译来的 xff0c 实际可以称为CPU绑定 在多核运
  • Docker 快速入门

    x1f389 Docker 简介和安装 Docker 快速入门 https blog csdn net weixin 45043334 category 11863858 html https blog csdn net weixin 45
  • 如何提高Linux的实时性

    QNX是黑莓旗下的一款微内核实时操作系统 xff0c 是全球第一款通过ISO 26262 ASIL levelD安全认证的车载操作系统 xff0c QNX是一个分布式 嵌入式 可规模扩展的实时操作系统 它遵循POSIX 1 程序接口 和PO
  • 自旋锁和互斥锁的区别

    面试官 xff1a 你说说互斥锁 自旋锁 读写锁 悲观锁 乐观锁的应用场景 百度安全验证 自旋锁和互斥锁的区别 一缕阳光a的博客 CSDN博客 自旋锁和互斥锁的区别 POSIX threads 简称Pthreads 是在多核平台上进行并行编