首页 文章 精选 留言 我的

精选列表

搜索[高并发],共10000篇文章
优秀的个人博客,低调大师

Java并发编程专题系列之从源码分析Mutex锁的运行原理

并行编程之条件变量(posix condition variables) 在整理Java LockSupport.park()的东东,看到了个"Spurious wakeup",重新梳理下。 #include <pthread.h> struct msg { struct msg *m_next; /* ... more stuff here ... */ }; struct msg *workq; pthread_cond_t qready = PTHREAD_COND_INITIALIZER; pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; void process_msg(void) { struct msg *mp; for (;;) { pthread_mutex_lock(&qlock); while (workq == NULL) pthread_cond_wait(&qready, &qlock); mp = workq; workq = mp->m_next; pthread_mutex_unlock(&qlock); /* now process the message mp */ } } void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); pthread_cond_signal(&qready); } 一个简单的消息生产者和消费者的代码,它们之间用condition同步。 这个代码最容易让人搞混的是process_msg函数里的pthread_mutex_lock 和pthread_mutex_unlock 是一对函数调用,前面加锁,后面解锁。的确,是加锁解锁,但是它们两不是一对的。它们的另一半在pthread_cond_wait函数里。 pthread_cond_wait函数可以认为它做了三件事: 把自身线程放到condition的等待队列里,把mutex解锁; 等待被唤醒(当其它线程调用pthread_cond_signal或者pthread_cond_broadcast时); 被唤醒之后,对mutex加锁,再返回。 mutex和condition实际上是绑定在一起的,一个condition只能对应一个mutex。 在Java的代码里,Condition对象只能通过lock.newCondition()的函数来获取。 Spurious wakeup 所谓的spurious wakeup,指的是一个线程调用pthread_cond_signal(),却有可能不止一个线程被唤醒。 假定有三个线程,线程A正在执行pthread_cond_wait,线程B正在执行pthread_cond_signal,线程C正准备执行pthread_cond_wait函数。 pthread_cond_wait(mutex, cond): value = cond->value; /* 1 */ pthread_mutex_unlock(mutex); /* 2 */ pthread_mutex_lock(cond->mutex); /* 10 */ if (value == cond->value) { /* 11 */ me->next_cond = cond->waiter; cond->waiter = me; pthread_mutex_unlock(cond->mutex); unable_to_run(me); } else pthread_mutex_unlock(cond->mutex); /* 12 */ pthread_mutex_lock(mutex); /* 13 */ pthread_cond_signal(cond): pthread_mutex_lock(cond->mutex); /* 3 */ cond->value++; /* 4 */ if (cond->waiter) { /* 5 */ sleeper = cond->waiter; /* 6 */ cond->waiter = sleeper->next_cond; /* 7 */ able_to_run(sleeper); /* 8 */ } pthread_mutex_unlock(cond->mutex); /* 9 */ 线程A执行了第1,2步,这时它释放了mutex,然后线程B拿到了这个mutext,并且pthread_cond_signal函数时执行并返回了。 于是线程B就是一个所谓的“spurious wakeup”。 /build/buildd/eglibc-2.19/nptl/pthread_cond_wait.c /build/buildd/eglibc-2.19/nptl/pthread_cond_signal.c wait morphing优化 从而会有一个叫“wait morphing”优化,就是如果线程被唤醒但是不能获取到mutex,则线程被转移(morphing)到mutex的等待队列里。 The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() orpthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked bythe thread calling pthread_cond_broadcast() or pthread_cond_signal(). 是先调用pthread_mutex_unlock,再调用pthread_cond_signal。 void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); pthread_cond_signal(&qready); } 有的地方给出的是先调用pthread_cond_signal,再调用pthread_mutex_unlock: void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_cond_signal(&qready); pthread_mutex_unlock(&qlock); } 先unlock再signal,这有个好处,就是调用enqueue_msg的线程可以再次参与mutex的竞争中,这样意味着可以连续放入多个消息,这个可能会提高效率。类似Java里ReentrantLock的非公平模式。 先signal再unlock,有可能会出现一种情况是被signal唤醒的线程会因为不能马上拿到mutex(还没被释放),从而会再次休眠,这样影响了效率。 可见在调用signal之前,可以不持有mutex,除非是“predictable scheduling”,可预测的调度行为。这种可能是实时系统才有这种严格的要求。 为什么要用while循环来判断条件是否成立? while (workq == NULL) pthread_cond_wait(&qready, &qlock); 而不用if来判断? if (workq == NULL) pthread_cond_wait(&qready, &qlock); 一个原因是spurious wakeup,但即使没有spurious wakeup,也是要用While来判断的。 线程A,线程B在pthread_cond_wait函数中等待,然后线程C把消息放到队列里,再调用pthread_cond_broadcast,然后线程A先获取到mutex,处理完消息完后,这时workq就变成NULL了。 线程B才获取到mutex,那么这时实际上是没有资源供线程B使用的。所以从pthread_cond_wait函数返回之后,还是要判断条件是否成功,如果成立,再进行处理。 pthread_cond_signal和pthread_cond_broadcast 认为调用pthread_cond_broadcast来唤醒所有的线程是比较好的写法。 但是我认为pthread_cond_signal和pthread_cond_broadcast是两个不同东东,不能简单合并在同一个函数调用。 只唤醒一个效率和唤醒全部等待线程的效率显然不能等同。典型的condition是用CLH或者MCS来实现的,要通知所有的线程,则要历遍链表,显然效率降低。 mutex,condition是不是公平(fair)的? #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; volatile int mutexCount = 0; void mutexFairTest(){ int localCount = 0; while(1){ pthread_mutex_lock(&lock); __sync_fetch_and_add(&mutexCount, 1); localCount += 1; if(mutexCount > 100000000){ break; } pthread_mutex_unlock(&lock); } pthread_mutex_unlock(&lock); printf("localCount:%d\n", localCount); } int main() { pthread_mutex_lock(&lock); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_mutex_unlock(&lock); sleep(100); } 输出结果是: localCount:16930422 localCount:16525616 localCount:16850294 localCount:16129844 localCount:17329693 localCount:16234137 连续调用pthread_cond_signal,会唤醒多少次/多少个线程? 比如线程a,b 在调用pthread_cond_wait之后等待,然后线程c, d同时调用pthread_cond_signal,那么a, b线程是否都能被唤醒? 会不会出现c, d, a 这种调用顺序,然后b一直在等待,然后死锁了? The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond). 因此,如果有线程已经在调用pthread_cond_wait等待的情况下,pthread_cond_signal调用至少会唤醒等待中的一个线程。 所以不会出现上面的线程b一直等待的情况。

优秀的个人博客,低调大师

如何最大化调优单台服务器的并发能力?

如下图片详细的描述了单台服务器的硬件配置和Nginx配置、Tomcat配置,以及文件句柄数信息。 1.以目前的情况如何再次把服务器整体性能优化到最优? 2.目前文件句柄数修改之后,设置不上,各种方法都试过了。 Nginx配置参数 Nginx分发Tomcat配置 Tomcat目前的配置参数 CPU信息 文件句柄数信息 修改文件句柄数,但是修改不了 系统运行时情况

优秀的个人博客,低调大师

Linux Lab 发布 v0.3,简化操作接口并发布首份中文手册

Linux Lab是一套用于 Linux 内核学习、开发和测试的即时实验室,可以极速搭建和使用,功能强大,用法简单! 可以用它来高效地学习处理器架构、Linux 内核、嵌入式 Linux 系统、C 语言编程、Linux 汇编、Shell 编程等。 Linux Lab Boot example 已经跃跃欲试了?!快来看看: Linux Lab v0.3 中文手册 Linux Lab v0.3 英文手册 Linux Lab:难以抗拒的十大理由 如果您想学习 Linux 0.11 内核和 Linux X86 汇编语言,也可以访问另外两套 Lab,即Linux 0.11 Lab和CS630 Qemu Lab。 版本更新 Linux Lab 先后于 6 月 29 日和 10 月 30 日发布了v0.1和v0.2正式版。 在过去数个月内,Linux Lab 连续发布了 v0.3 的 3 个候选版本,本次发布v0.3 正式版。 本次 v0.3-rc3 ~ v0.3 之间有 119 笔变更,整个 v0.2 ~ v0.3 之间有 366 笔变更,期间有多位贡献者提交了 Pull Request,参与了项目测试和试用,并提出了改进建议,非常感谢大家的参与和贡献: $ git log --format='%aN' v0.2..HEAD | sort -u LastRitter unicornx Wu Zhangjin $ git log --oneline v0.2..HEAD | wc -l 366 本次主要更新如下: 统一了所有组件的公共操作接口更方便记忆 新增了make cmd [kernel|uboot|root|qemu] [option=value]操作方式 例如:make defconfig kernel等同于make kernel-defconfig 更多命令包括 download, checkout, patch, defconfig, menuconfig, build, boot, test, debug 进一步优化了大型仓库的下载体验 通过git init + fetch取代git clone 通过添加自动依赖关系简化了命令执行并大幅度提升实验效率 make boot build=kernel一条命令完成下载,检出版本,配置,编译,启动全过程 为多本知名 Linux 图书新增了 v2.6.10, v2.6.11, v2.6.12, v2.6.14, v2.6.21, v2.6.24 等多个历史版本内核 闲置在家的经典 Linux 图书不妨翻出来陪伴大家共克时艰 发布了首份中文版用户手册 重新梳理了文档布局并翻译成了中文 环境准备 在非 Ubuntu 平台,请提前自行安装好 docker,可参考Docker for Mac、Docker for Windows。 如果是老版本的 Windows,可以用Docker Toolbox,也可以通过 Virtualbox 或 Vmware 自行安装 Ubuntu。 国内的同学请务必使用国内的 Docker 镜像服务,否则无法正常下载镜像,推荐参考阿里云镜像配置文档。 极速体验 该版本依赖最新的 Cloud Lab 和 docker 镜像: $ git clone https://gitee.com/tinylab/cloud-lab.git $ cd cloud-lab $ tools/docker/pull linux-lab # 确保更新 docker 镜像 $ tools/docker/run linux-lab 已经下载过的,请更新到最新版本并重启 Linux Lab: $ cd cloud-lab && git pull $ tools/docker/update linux-lab $ tools/docker/rerun linux-lab 进去以后,打开控制台,敲入如下命令即可启动一个板子(自动下载预编译的版本): $ make boot 一键编译(自动下载源码、检出版本、打补丁、配置、编译): $ make boot build=kernel 关键特性 Linux Lab 具备如下特性: 支持 3 大操作系统(Windows、MacOS、Linux),可以轻松在这三大操作系统下使用。 支持 7+ 大处理器架构(X86、ARM、MIPS、PPC、CSKY,RISC-V, LOONGSON),其中 LOONGSON 和 CSKY 为国产处理器。 支持 15+ 款开发板(i386/pc, x86_64/pc, arm/versatilepb, arm/vexpress-a9, ppc/g3beige, mips/malta, aarch64/virt, aarch64/raspi3, riscv32/virt, riscv64/virt, csky/virt, loongson/ls1b, loongson/ls2k, loongson/ls232, loongson/ls3a7a)。 支持 5 种登陆方式(docker, ssh, vnc,webssh, webvnc),可以本地访问,也可以远程访问。 集成了 5 大组件(Qemu、U-boot、Buildroot、Linux、Toolchain),都有预编译版本。 内置了 5 大平台,32 位和 64 位共 10 个 Hello World 汇编语言例程,见examples/assembly。 可以学习处理器指令集、Qemu、Shell、汇编、C、Linux 内核、嵌入式 Linux。 支持 Debugging 和 Testing。 host & guest 双侧免 root 使用。 更多信息: 项目首页 Homepage:http://tinylab.org/linux-lab 项目社群 联系微信:tinylab 联系公号:泰晓科技 Linux Lab 用户交流群 Linux Lab 开发者 项目仓库 Gitee:https://gitee.com/tinylab/linux-lab Github:https://github.com/tinyclub/linux-lab 项目插件 CSKY(中天微):https://gitee.com/tinylab/csky LOONGSON(龙芯):https://gitee.com/loongsonlab/loongson 演示视频 基本用法:Linux 快速上手 学习汇编:AT&T 汇编上手 学习Uboot:Uboot 快速上手 ARM 开发:在 arm/vexpress-a9 上运行 Ubuntu 18.04 LTS RISC-V开发:使用 riscv32/virt 和 riscv64/virt 开发板 龙芯开发:在 Linux Lab 上使用龙芯 ls2k 平台 特性开发:一条命令测试和体验某个内核特性 模块开发:一条命令配置、编译和测试内核模块 内核调试:所有板子的调试功能自测视频 内核测试:所有当前预置板子的启动过程自测视频 该项目完全开源,以 GPL 2.0 协议发布,欢迎所有高校、企业、个人用户使用或者参与开发。 欢迎通过微信号(tinylab)联系我们,联系后可以获邀进Linux Lab 用户交流群和Linux Lab 开发者群,还将获赠 Linux Lab 安装文档和 Linux Lab 大会演讲幻灯片。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册