Linux下线程同步(带你了解什么是互斥锁、死锁、读写锁、条件变量、信号量等)

2023-11-01

线程同步概念

假设有四个线程A、B、C、D,当前一个线程A对内存中的共享资源进行访问的时候,其他线程B、C、D都不可以对这块内存进行操作,直至A对这块内存访问完毕为止,B、C、D中的一个才能访问这块内存,剩余的俩个需要继续阻塞等待,一次类推,直到所有的线程都对这块内存操作完毕。线程对内存的这种访问方式称为线程同步,所谓的现成的同步并不是多个线程同时对内存访问,而是按照先后顺序依次进行的。

源码:
在这里插入图片描述

结果图:
在这里插入图片描述

CPU对于寄存器、一级缓存、二级缓存、三级缓存是独占的。用于存储处理的数据和线程的状态信息,数据被处理完需要再次被写入到物理内存中,物理内存数据也可以通过文件IO操作写入到磁盘中。

上述程序中,俩个线程共用全局变量number当线程变成运行态之后开始计数时,从物理内存(Memory)中加载数据,然后让数据放到CPU进行运算,最后将结果跟新到物理内存中。

如果线程A执行这个过程期间就失去了CPU时间片,线程A被挂起了最新的数据没能更新到物理内存中(保存到了寄存器中),线程B变成了运行态之后从物理内存读取数据,这个时候B拿的数据就不是最新数据。只能基于旧的数据往后计数,然后失去时间片。线程A在得到时间片变成运行态时,第一件事就是将上次没更新到内存的数据更新到内存(从寄存器拿上次),但是这样会导致B线程已经跟新到内存的数据被覆盖掉。活白干了。最终导致有些数据会被重复很多次。

在这里插入图片描述

同步方式

对于多个线程访问共享资源出现数据混乱的问题,需要进行线程同步。常用的线程同步方式有四种:互斥锁、读写锁、条件变量、信号量。所谓的共享资源就是多个线程共同访问的变量,这些变量通常为全局数据区变量或者堆区变量,这些变量对于的共享资源也被称之为临界资源。
在这里插入图片描述

互斥锁

互斥锁函数
互斥锁是线程同步最常用的一种方式,通过互斥锁可以锁定一个代码块,被锁定的这个代码块,所有线程只能顺序执行(不能并行处理),这样多线程访问共享资源数据混乱的问题就可以被解决了,需要付出的代价就是执行效率的降低,因为默认临界区多个线程可以并行处理的,现在只能串性处理。

在Linux中互斥锁的类型为pthread_mutex_t,创建一个这样类型的变量就得到了一把互斥锁。ptherad_mutex_t mutex;

在创建的锁对象中保存了当前这把锁的状态信息:锁定还是打开,如果是锁定状态还记录了给这把锁加锁的线程信息(线程ID)。一个互斥锁变量只能被一个线程锁定,被锁定之后其他线程再对互斥锁变量加锁就会被阻塞,直到这把互斥锁被解锁,被阻塞的线程才能被解除阻塞,一般情况下,每一个共享资源对应一把互斥锁,锁的个数与线程的个数无关

初始互斥锁: int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

释放互斥锁: int pthread_mutex_destroy(pthread_mutex_t *mutex);

restrict:关键字,用来修饰指针,只有这个关键字修饰的指针可以访问指向的内存地址。其他指针不行
mutex:互斥锁变量地址
attr:互斥锁的属性,一般使用默认属性就可以,这个参数指定NULL

修改互斥锁状态
int pthread_mutex_lock(pthread_mutex *mutex);
该函数被调用时,首先会判断参数mutex互斥锁中的状态是不是锁定状态。
• 若没有被锁定,时打开的。这个线程可以加锁成功。该锁会记录那个线程加锁成功了
• 锁被锁定了,其他线程加锁就会失败,这些线程就会阻塞到这把锁上。
• 当把这把锁解开之后,阻塞在这把锁的线程就解除阻塞了,并且这些线程通过竞争的方式对这把锁加锁,没抢到锁的线程继续阻塞。
例如:你要去上厕所,发现里面有人,你就在外边等着。

尝试加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
• 如果这把锁没有被锁定,线程加锁成功
• 如果这把锁被锁定后了。调用这个函数加锁的线程,不会被阻塞,加锁失败直接返回错误码。
例如:你要去上厕所,发现里面有人,你就去干别的事情了,

互斥锁解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
那个线程加的锁,必须那个线程去解锁。

互斥锁的使用

需要先创建一个互斥锁
在这里插入图片描述
再使用互斥锁对需要加锁的位置进行加锁和解锁操作。
在这里插入图片描述

全部代码如下:
在这里插入图片描述
运行图如下:
在这里插入图片描述

死锁

当多个线程访问共享资源时,需要加锁,如果锁使用不当,就会造成死锁现象。如果线程死锁造成的后果是:所有线程都被阻塞,并且线程的阻塞是无法解开的(因为可以解锁的线程也被阻塞了)。

例如:加锁后忘记解锁
在这里插入图片描述
再例如:

  1. 当我们加锁后进入if语句后退出(return)了,等其他线程再进来就发现当前已被锁,就阻塞自己。
  2. 重复加锁(多加锁了一次)

多个线程对一个临界资源进行访问我们需要一把锁
一个线程对多个临界资源进行访问我们需要多把锁

如何避免死锁:
• 对共享资源访问完毕之后,一定要解锁。或者在加锁的时候使用tylock
• 如果程序中有多把锁,可以控制对锁的访问顺序(顺序访问共享资源,但是有些情况下是做不到的),另外也可以在对其他互斥锁操作前,先释放当前线程拥有的互斥锁。
• 项目程序中可以引入一些专门用于检测死锁的模块

读写锁

读写锁是一把锁,是互斥锁的升级版。在做读操作的时候可以提高程序执行效率,如果所有的线程都是做读操作,那么读是并行的,但是使用互斥锁,读操作也是串行的。

锁的类型为pthread_rwlock_t 这把锁既可以锁定读操作,还可以锁定写操作。
记录信息:

  1. 锁的状态:锁定/打开
  2. 锁定的是什么操作:读操作/写操作,使用了读写锁锁定了读操作,需要先解锁,再去锁定写操作。
  3. 哪个线程将这把锁锁上的

特点:
• 使用了读写锁的读锁锁定了临界区,线程对临界区的访问是并行的。读锁是共享的。
• 使用了读写锁的写锁锁定了临界区,线程对临界区的访问时串性的。写锁是独占的。
• 使用了读写锁分别对俩个临界区区加了读锁和写锁,俩个线程要同时访问着俩个临界区,访问写锁临界区的线程继续运行,访问读锁临界区的线程阻塞,因为写锁比读锁的优先级高。

如果说程序中所有的线程都对共享资源做写操作,使用读写锁没有优势。但是说程序中所有的线程对共享资源既有读也有写操作,使用读写锁更有优势。

初始化读写锁
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlock_t *restrict attr);

rwlock:读写锁地址,传出参数
attr:读写锁属性,一般使用默认属性,指定为NULL

释放读写锁占用的系统资源
int pthread_rwlock_destroy(pthread_rwlock_t *restrict rwlock);

rwlock:读写锁地址,传出参数

加锁读操作
int pthread_rwlock_rdlock(pthread_rwlock_t * );
如果读写锁是打开的,那么加锁成功,
如果读写锁锁定了读操作,调用这个函数依然可以加锁成功,因为读锁是共享的。
如果读写锁锁定了写操作,调用这个函数会阻塞。

如果加读锁失败,不会阻塞当前线程,直接返回错误号 有效避免死锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock);
如果读写锁是打开的,那么加锁成功,
如果读写锁锁定了读操作,调用这个函数依然可以加锁成功,因为读锁是共享的。
如果读写锁锁定了写操作,不会阻塞当前线程,函数会返回一个错误码。

加锁写操作
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
如果读写锁是打开的,那么加锁成功,
如果读写锁锁定了读操作,调用这个函数会阻塞。
如果读写锁锁定了写操作,调用这个函数会阻塞。

如果加锁失败,不会阻塞当前线程,直接返回错误号 有效避免死锁
int pthread_rwlock_trywrdlock(pthread_rwlock_t * rwlock);
如果读写锁是打开的,那么加锁成功,
如果读写锁锁定了读操作,不会阻塞当前线程,函数会返回一个错误码。
如果读写锁锁定了写操作,不会阻塞当前线程,函数会返回一个错误码。

解锁 读锁写锁都可以
int pthread_rwlock_unlock(pthread_rwlock_t * rwlock);

读写锁使用

题目要求:8个线程操作同一个全局变量,3个线程不定时写同一全局资源,5个线程不定时读同一线程。
源码如下:
在这里插入图片描述
运行效果图:
在这里插入图片描述

条件变量

条件变量函数
条件变量的主要作用不是处理线程同步,而是进行线程阻塞。如果多线程程序中只使用条件变量无法实现线程的同步,必须要配合互斥锁来使用。虽然条件变量和互斥锁都能阻塞线程,但是二者的效果是不一样得到,二者的区别如下:
• 假设有A-Z26个线程,这26个线程共同访问同一把互斥锁,如果A线程加锁成功,那么其余B-Z线程访问互斥锁都阻塞,所有的线程只能顺序访问临界区。
• 条件变量只有在满足指定条件下才会阻塞线程,如果条件不满足,多个线程可以同时进入临界区,同时读写临界区资源,这种情况下还是会出现共享资源中数据混乱。

一般情况下条件变量用于处理生产者和消费者模型,并且和互斥锁配合使用,条件变量类型对应的类型为pthread_cond_t

被条件变量阻塞的线程的信息会被记录到这个变量中,以便在解除阻塞的时候使用。

初始化
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
cond:条件变量的地址
attr:条件变量属性,一般使用默认属性,指定为NULL

销毁释放资源
int pthread_cond_destroy(pthread_cond_t *cond);
cond:条件变量的地址

阻塞函数
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex *restrict mutex);
该函数在阻塞线程的时候,需要一个互斥锁参数,这个互斥锁主要功能是进行线程同步,让线程顺序进入临界区,避免出现数共享资源的数据混乱。会对互斥锁做俩件事
• 1、在阻塞线程时候,如果线程已经对互斥锁mutex上锁,那么会将这把锁打开,这样避免死锁。
• 2、当线程解除阻塞的时候,函数内部会帮助这个线程再次将这个mutex互斥锁锁上,继续向下访问临界区。

阻塞时长函数
将线程阻塞一定时长,时间到了,线程就解除阻塞。

struct timespec{
time_t tv_sec;   
time_t tv_nsec;
};

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
前俩个参数和前面阻塞哈数一样,第三个参数是阻塞时长,

唤醒阻塞函数(至少唤醒一个)
int pthread_cond_signal(pthread_cond_t *cond);

唤醒阻塞函数(全部唤醒)
int pthread_cond_broadcast(pthread_cond_t *cond);

生产者和消费者

场景描述:使用条件变量实现生产者和消费者模型,生产者有5个,往链表头部添加节点,消费者也有5个,删除链表尾巴的节点
在这里插入图片描述
源码如下:
在这里插入图片描述
接下里我们该做线程同步问题
• 生产者和消费者区域全部上锁
• 当生产者发现生产数量超过5时,阻塞生产者,唤醒消费者。当生产者生产完毕,也需要唤醒消费者。
• 当消费者发现没有产品时,阻塞消费者,唤醒生产者。当消费者消费完毕,也需要唤醒生产者

在这里插入图片描述

信号量

信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。信号量不一定是锁定某一个资源,而是流程上的概念,比如:有 A,B 两个线程,B 线程要等 A 线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。流水线

信号量(信号灯)与互斥锁和条件变量的主要不同在于” 灯” 的概念,灯亮则意味着资源可用,灯灭则意味着不可用。信号量主要阻塞线程,不能完全保证线程安全,如果要保证线程安全,需要信号量和互斥锁一起使用。

信号量和条件变量一样用于处理生产者和消费者模型,用于阻塞生产者线程或者消费者线程的运行。
信号的类型为 sem_t 对应的头文件为 <semaphore.h>

初始化信号量/信号灯
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:信号量变量地址
pshared:0线程同步,非0进程同步
value:初始化当前信号量拥有的资源数(>=0),如果资源数位0,线程就会被阻塞了。

资源释放,线程销毁之后调用这个函数
int sem_destroy(sem_t *sem);

消耗函数
int sem_wait(sem_t *sem); 函数调用时sem中的资源就会被消耗一个,资源数-1
当线程调用这个函数,并且sem>0,线程不会被阻塞,线程会占用sem中的一个资源,因此资源数-1,直到sem中的资源数减为0时。资源被耗尽,因此线程也就被阻塞了。

int sem_trywait(sem_t *sem); 函数调用时sem中的资源就会被消耗一个,资源数-1
当线程调用这个函数,并且sem>0,线程不会被阻塞,线程会占用sem中的一个资源,因此资源数-1,直到sem中的资源数减为0时。资源被耗尽,但是线程不会被阻塞,直接返回错误号,因此可以在程序中添加判断分支,用于处理获取资源失败之后的情况。

解除阻塞时间函数
// 表示的时间是从1971.1.1到某个时间点的时间, 总长度使用秒/纳秒表示

struct timespec {
time_t tv_sec;      /* Seconds */
long   tv_nsec;     /* Nanoseconds [0 .. 999999999] */
};

// 调用该函数线程获取sem中的一个资源,当资源数为0时,线程阻塞,在阻塞abs_timeout对应的时长之后,解除阻塞。
// abs_timeout: 阻塞的时间长度, 单位是s, 是从1970.1.1开始计算的
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

该函数的参数 abs_timeout 和 pthread_cond_timedwait 的最后一个参数是一样的,使用方法不再过多赘述。当线程调用这个函数,并且 sem 中的资源数 >0,线程不会阻塞,线程会占用 sem 中的一个资源,因此资源数 - 1,直到 sem 中的资源数减为 0 时,资源被耗尽,线程被阻塞,当阻塞指定的时长之后,线程解除阻塞。

增加资源函数
// 调用该函数给sem中的资源数+1
int sem_post(sem_t *sem);
调用该函数会将 sem 中的资源数 +1,如果有线程在调用 sem_wait、sem_trywait、sem_timedwait 时因为 sem 中的资源数为 0 被阻塞了,这时这些线程会解除阻塞,获取到资源之后继续向下运行。

查看信号量函数
// 查看信号量 sem 中的整形数的当前值, 这个值会被写入到sval指针对应的内存中
// sval是一个传出参数
int sem_getvalue(sem_t *sem, int *sval);

生产者消费者(一个资源量)

一个资源量就不需要线程同步。必然是单线程 , 只有资源总数为1时候,才可以不加锁
源代码:
在这里插入图片描述

生产者消费者(多个资源)

需要加锁,生产者和消费者共用一个链表,所以用一把锁。
锁要在信号量里面。不然有可能会造成死锁(比如:现在资源被消费完毕。然后一直被消费者抢到,进入阻塞,当全部线程被阻塞在消费者这边时,就造成了死锁)

源代码:
在这里插入图片描述

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

Linux下线程同步(带你了解什么是互斥锁、死锁、读写锁、条件变量、信号量等) 的相关文章

  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • ubuntu:升级软件(cmake)-版本消歧(本地编译)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我的机器上安装了 cmake 2 8 0 来自 ubuntu 软件包 二进制文件放置在 usr bin cmake 中 我需要将 cmake 版本至少
  • 如何通过保持目录结构完整来同步路径中匹配模式的文件?

    我想将所有文件从服务器 A 复制到服务器 B 这些文件在不同级别的文件系统层次结构中具有相同的父目录名称 例如 var lib data sub1 sub2 commonname filetobecopied foo var lib dat
  • 如何授予 apache 使用 NTFS 分区上的目录的权限?

    我在一台带有 20GB 硬盘的旧机器上运行 Linux Lubutu 12 10 我有一个 1 TB 外部硬盘 上面有一个 NTFS 分区 在该分区上 有一个 www 目录 用于保存我的网页内容 它在启动时自动安装为 media t515
  • 为什么我可以直接从 bash 执行 JAR?

    我是一个长期从事 Java 工作的人 并且知道运行带有主类的 JAR 的方法MANIFEST MFJar 中的文件很简单 java jar theJar jar 我用它来启动 Fabric3 服务器 包含在bin server jar在其标
  • PHP 无法打开流:是一个目录

    非常简单的 PHP 脚本 我在我亲自设置的 Ubuntu Web 服务器上的 EE 模板中运行 我知道这与权限有关 并且我已经将我尝试写入的目录的所有者更改为 Apache 用户 我得到的错误是 遇到 PHP 错误 严重性 警告 消息 fi
  • 在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403

    我使用的是 Linux Elementary OS 并在 opt 中安装了 lampp My CSS and JS won t load When I inspect my page through browser The console
  • 按进程名称过滤并记录 CPU 使用情况

    Linux 下有选项吗顶部命令 https www man7 org linux man pages man1 top 1 html我可以在哪里按名称过滤进程并将每秒该进程的 CPU 使用情况写入日志文件 top pgrep 过滤输出top
  • 我如何知道 C 程序的可执行文件是在前台还是后台运行?

    在我的 C 程序中 我想知道我的可执行文件是否像这样在前台运行 a out 或者像这样 a out 如果你是前台工作 getpgrp tcgetpgrp STDOUT FILENO or STDIN FILENO or STDERR FIL
  • 监视目录的更改

    很像一个类似的问题 https stackoverflow com questions 112276 directory modification monitoring 我正在尝试监视 Linux 机器上的目录以添加新文件 并希望在这些新文
  • 如果在等待“read -s”时中断,在子进程中运行 bash 会破坏 tty 的标准输出吗?

    正如 Bakuriu 在评论中指出的那样 这基本上与BASH 输入期间按 Ctrl C 会中断当前终端 https stackoverflow com questions 31808863 bash ctrlc during input b
  • 快速像素绘图库

    我的应用程序以每像素的方式生成 动画 因此我需要有效地绘制它们 我尝试过不同的策略 库 但结果并不令人满意 尤其是在更高分辨率的情况下 这是我尝试过的 SDL 好的 但是慢 OpenGL 像素操作效率低下 xlib 更好 但仍然太慢 svg
  • 在 Mac OSX 上交叉编译 x86_64-unknown-linux-gnu 失败

    我尝试将我的 Rust 项目之一编译到 x86 64 unknown linux gnu 目标 cargo build target x86 64 unknown linux gnu Compiling deployer v0 1 0 fi
  • 监控子进程的内存使用情况

    我有一个 Linux 守护进程 它分叉几个子进程并监视它们是否崩溃 根据需要重新启动 如果父进程可以监视子进程的内存使用情况 以检测内存泄漏并在超出一定大小时重新启动子进程 那就太好了 我怎样才能做到这一点 您应该能够从 proc PID
  • git 错误:无法处理 https

    当我尝试使用 git clone 时https xxx https xxx我收到以下错误我不处理协议 https 有人可以帮我吗 完整消息 dementrock dementrock A8Se git 克隆https git innosta
  • 当用户按下打印时运行脚本,并且在脚本结束之前不开始假脱机(linux,cups)

    我需要做的是结合用户按下打印来执行 python 程序 脚本 并且在该程序退出之前不要让打印作业假脱机 原因是打印驱动程序不是开源的 我需要更改用户设置 在本例中是部门 ID 和密码 通常是每个用户 但因为这是一个信息亭 具有相同帐户的不同
  • 如何从 PROC 获取有关子进程的信息

    我正在尝试编写一个以几个进程作为参数的程序 然后父进程执行每个子进程并打印出一些相关的统计信息 示例 generate ls l 将生成一个程序 打印出有关 ls l 的一些统计信息 特别是其系统时间 用户时间和上下文切换次数 我不想使用
  • vagrant ssh -c 并在连接关闭后保持后台进程运行

    我正在编写一个脚本来启动和后台流浪机器内的进程 似乎每次脚本结束和 ssh 会话结束时 后台进程也会结束 这是我正在运行的命令 vagrant ssh c cd vagrant src nohup python hello py gt he
  • Fedora dnf 更新不起作用?

    当我尝试使用 update 命令更新 Fedora 22 时 sudo dnf update 我收到以下错误 错误 无法同步存储库 更新 的缓存 无法准备内部镜像列表 Curl 错误 6 无法解析主机名 无法解析主机 mirrors fed

随机推荐

  • apisix高性能网关-中文开发文档

    2020年6月12日13 48 33 github https github com apache incubator apisix 目前此项目已有成为apache孵化项目 官方中文文档 https github com apache in
  • 拓展人脉,把握机会,摆脱“孔乙己的长衫”

    孔乙己的长衫 学历究竟成为敲门砖还是枷锁 孔乙已是鲁迅笔下人物 穷困流倒还穿着象征读书人的长衫 迁腐 麻木 最近 大家自我调佩是 当代孔乙己 学历成为思想负担 找工作时高不成低不就 我将从以下几个方面来说一说我对这方面的看法 我认为 在当今
  • 1. 两数之和

    目录 给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 数组中同一个元素在答案里不能重复出现 你可以按
  • 数据结构--计算表达式完整版(涉及乘方)

    思路 两个栈 数据栈与符号栈 在描述优先级时 我们将加减描述为 I级 乘除为 II既 乘方为 III级 1 在之前的只有加减乘除的计算表达式里 就有了初步思路 当我们要计算的时候 局部计算函数 数字栈与符号栈 分别在数字栈顶取出两个操作数
  • i2c_SLAVE

    driver driver通过I2C的接口与DUT相连 负责接收DUT通过接口传来的地址数据等读写信息并作出反应 将sequencer中传来的trans中的数据驱动到总线上并根据设置的ack和nack作出回应 将总线上写来的数据存到tran
  • Visual Studio 2019 C语言程序(VS2019 C语言)

    新的Visual Studio 2019出来已经有一段时间了 博主也是一开始就从vs2017换到了vs2019 发现整体的操作流程还是有一定的改变 因为之前发表过一个vs2017的博客 对Visual Studio IDE和风格确实非常喜欢
  • Qt5 通过 QFtp 实现 Ftp文件下载

    在Qt5环境下使用自编译的QFtp库 参考官方提供的实例 对部分内容进行更改 实现了Ftp下载文件的客户端 详细代码如下 h头文件 ifndef FTPWINDOW H define FTPWINDOW H include
  • linux下查看某服务端口对应的进程ID

    Linux下查看某端口号所对应的进程ID 使用lsof命令 格式为 lsof i 端口号 例如 lsof i 30000 root Web Service CAServer lsof i 30000 COMMAND PID USER FD
  • oracle的io优化--db_writer_processes & dbwr_io_slaves对比

    author skate time 2011 09 29 db writer processes 和 dbwr io slaves对比 在计算机世界里 磁盘的发展速度远低于cpu memory 磁盘io现在已经成为计算机的瓶颈 对于orac
  • 揭密微信跳一跳小游戏那些外挂

    欢迎大家前往云 社区 获取更多腾讯海量技术实践干货哦 作者 Hahn 腾讯高级UI工程师 由 WeTest质量开放平台团队 发布于云 社区 WeTest 导读 张小龙 这个游戏发布以后 其实它的效果有点超出我们的预期 我们自己开玩笑说 这个
  • mysql数据表查询操作

    数据表查询操作 准备工作 导入之前需要先创建一个数据库 数据库资料传送门 使用新创建的数据库 使用 source 文件地址 导入数据 create database db charset utf8 use db source home py
  • win10网上邻居看不到别的共享电脑怎么样办

    https jingyan baidu com article 4853e1e5b714aa1909f72600 html 转载于 https www cnblogs com kuangke p 10901469 html
  • 【Dom获取&属性操作】JavaScript 全栈体系(十)

    Web APIs 第四章 操作元素属性 一 操作元素常用属性 还可以通过 JS 设置 修改标签元素属性 比如通过 src更换 图片 最常见的属性比如 href title src 等 语法 对象 属性 值
  • python+appium自动化测试-pytest+allure测试报告(一)

    来自APP Android端自动化测试初学者的笔记 写的不对的地方大家多多指教哦 一 Allure安装 1 pytest和allure插件安装 pip install allure pytest pip install pytest 2 A
  • python3+robotframework+selenium3 浏览器兼容性测试

    robot framework 测试浏览器兼容性 目前ride已支持一下浏览器 firefox ie chrome safari 本次我们已win 10中的ie为例 来看看如何使用python3 robotframework seleniu
  • 我是如何从通信转到Java软件开发工程师的?

    我的CSDN和公众号的读者里面有绝大部分都是在校学生 有本科的 也有专科的 我在微信里收到很多读者的提问 大部分问题都跟如何学习编程有关 有换专业自学的 有迷茫不知道如何学习的 有报培训班没啥效果的等等 我能感受到他们的诚意和焦虑 所以我觉
  • 哪些情况可以终止线程呢

    目录 哪些情况可以终止线程的进行 题目解析 线程结束的三个原因 线程结束的三种方法 具体分析 1 使用标志位推出线程 2 使用stop方法强制终止线程 3 使用interrupt终止线程 哪些情况可以终止线程的进行 题目解析 答案选C A
  • Kotlin常用的高阶函数(Filter、TakeWhile、Let、Apply、With......)

    一 Filter package net println kotlin chapter5 builtins author wangdong description Kotlin常见的高阶函数 fun main args Array
  • 内核的并发和竞态(信号量、completion、自旋锁)

    1 并发和并行 1 并行 在同一时刻有多个线程一起运行 2 并发 在同一时刻只有一个线程在运行 但是在一个时间段内有多个线程运行 总结 并发是宏观的并行 因为CPU运行特别快 虽然CPU不断在切换运行的线程 但是对于人来说 根本感知不到CP
  • Linux下线程同步(带你了解什么是互斥锁、死锁、读写锁、条件变量、信号量等)

    线程同步概念 假设有四个线程A B C D 当前一个线程A对内存中的共享资源进行访问的时候 其他线程B C D都不可以对这块内存进行操作 直至A对这块内存访问完毕为止 B C D中的一个才能访问这块内存 剩余的俩个需要继续阻塞等待 一次类推