Linux:soft lockup 检测机制
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. 分析背景
本文分析基于 linux-4.14.132 内核代码分析,运行环境 Ubuntu 16.04.4 LTS + QEMU + ARM vexpress-a9 ,rootfs 基于 ubuntu-base-16.04-core-armhf.tar.gz 制作。
3. soft lockup 机制
3.1 什么是 soft lockup ?
soft lockup 是指某个进程一直占住当前 CPU ,其它进程无法在当前 CPU 上得到调度的情形。soft lockup 在不同的抢占模式下,有着不同的情形。
3.2 各种抢占配置下的 soft lockup
3.2.1 CONFIG_PREEMPT_NONE 配置下的 soft lockup
CONFIG_PREEMPT_NONE 不支持内核态抢占,致力于提高吞吐量,通常用于服务器。 。在 CONFIG_PREEMPT_NONE 配置下,包含死循环的进程,可导致 soft lockup 。
3.2.2 CONFIG_PREEMPT 配置下的 soft lockup
CONFIG_PREEMPT 支持内核态抢占,用于低延迟的桌面系统。在CONFIG_PREEMPT 配置下,较长时间禁用抢占的进程,可导致 soft lockup 。
3.2.3 CONFIG_PREEMPT_VOLUNTARY 配置下的 soft lockup
CONFIG_PREEMPT_VOLUNTARY 不支持内核态抢占,通常用于桌面系统。相对于配置 CONFIG_PREEMPT_NONE 的情形,在一些可能导致睡眠的代码路径上,插入了一些调度点,以降低延迟。
/** include/linux/kernel.h*/...#ifdef CONFIG_PREEMPT_VOLUNTARY
extern int _cond_resched(void);
# define might_resched() _cond_resched()
#else
# define might_resched() do { } while (0)
#endif#ifdef CONFIG_DEBUG_ATOMIC_SLEEPvoid ___might_sleep(const char *file, int line, int preempt_offset);void __might_sleep(const char *file, int line, int preempt_offset);
/*** might_sleep - annotation for functions that can sleep** this macro will print a stack trace if it is executed in an atomic* context (spinlock, irq-handler, ...).** This is a useful debugging help to be able to catch problems early and not* be bitten later when the calling function happens to sleep when it is not* supposed to.*/
# define might_sleep() \do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
# define sched_annotate_sleep() (current->task_state_change = 0)
#elsestatic inline void ___might_sleep(const char *file, int line,int preempt_offset) { }static inline void __might_sleep(const char *file, int line,int preempt_offset) { }
# define might_sleep() do { might_resched(); } while (0)
# define sched_annotate_sleep() do { } while (0)
#endif#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)...
在 CONFIG_PREEMPT_VOLUNTARY 配置下,包含死循环的进程,可导致 soft lockup 。
3.3 soft lockup 的实现
3.3.1 创建 soft lockup watchdog 每 CPU 线程
为所有的 CPU 创建每 CPU 的 watchdog 内核线程,该内核线程每次被调度时更新一次 watchdog时间戳,同时启动一个定时器;定时器到期时,对比 watchdog时间戳 和 当前时间戳,如果(当前时间戳 - watchdog时间戳 >= 设定的soft lockup阈值),表示当前 CPU 上的当前进程已经占住 CPU 较长时间,如此报告一个 soft lockup 问题 。
void __init lockup_detector_init(void)
{...cpumask_copy(&watchdog_cpumask, cpu_possible_mask);...lockup_detector_setup();
}
static struct smp_hotplug_thread watchdog_threads = {.store = &softlockup_watchdog,.thread_should_run = watchdog_should_run,.thread_fn = watchdog,.thread_comm = "watchdog/%u",.setup = watchdog_enable,.cleanup = watchdog_cleanup,.park = watchdog_disable,.unpark = watchdog_enable,
};static __init void lockup_detector_setup(void)
{...lockup_detector_update_enable();.../** 创建每 CPU 的 watchdog 内核线程:* . 负责更新每 CPU 的 watchdog 时间戳; * . 每次更新 watchdog 时间戳的同时启动一个定时器,* 该定时器检测 watchdog 时间戳更新的时间间隔,如* 果更新间隔超过设定的阈值,则报告 soft lockup 问题。*/ret = smpboot_register_percpu_thread_cpumask(&watchdog_threads,&watchdog_allowed_mask);if (ret) {pr_err("Failed to initialize soft lockup detector threads\n");return;}mutex_lock(&watchdog_mutex);softlockup_threads_initialized = true;lockup_detector_reconfigure();mutex_unlock(&watchdog_mutex);
}
static void lockup_detector_update_enable(void)
{watchdog_enabled = 0;...if (soft_watchdog_user_enabled)watchdog_enabled |= SOFT_WATCHDOG_ENABLED;
}
int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread,const struct cpumask *cpumask)
{...for_each_online_cpu(cpu) {ret = __smpboot_create_thread(plug_thread, cpu); /* 创建 @cpu 的内核线程 */...if (cpumask_test_cpu(cpu, cpumask))smpboot_unpark_thread(plug_thread, cpu); /* 启动 @cpu 的内核线程,进入 smpboot_thread_fn() */}...
}
static int
__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
{struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);struct smpboot_thread_data *td;td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu));td->cpu = cpu;td->ht = ht;/* * SMP 内核线程的公共入口为 smpboot_thread_fn() , * 通过 smpboot_thread_fn() 调用具体的线程入口。*/tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu,ht->thread_comm);kthread_park(tsk); /* 暂停内核线程 */get_task_struct(tsk);*per_cpu_ptr(ht->store, cpu) = tsk;...return 0;
}
3.3.2 运行 soft lockup watchdog 内核线程
static int smpboot_thread_fn(void *data)
{struct smpboot_thread_data *td = data;struct smp_hotplug_thread *ht = td->ht; /* watchdog_threads */while (1) {set_current_state(TASK_INTERRUPTIBLE);preempt_disable();if (kthread_should_stop()) {__set_current_state(TASK_RUNNING);preempt_enable();/* cleanup must mirror setup */if (ht->cleanup && td->status != HP_THREAD_NONE)ht->cleanup(td->cpu, cpu_online(td->cpu));kfree(td);return 0;}if (kthread_should_park()) {__set_current_state(TASK_RUNNING);preempt_enable();if (ht->park && td->status == HP_THREAD_ACTIVE) {BUG_ON(td->cpu != smp_processor_id());ht->park(td->cpu);td->status = HP_THREAD_PARKED;}kthread_parkme();/* We might have been woken for stop */continue;}BUG_ON(td->cpu != smp_processor_id());/* Check for state change setup */switch (td->status) {case HP_THREAD_NONE:__set_current_state(TASK_RUNNING);preempt_enable();if (ht->setup)ht->setup(td->cpu); /* watchdog_enable(): 初始化 watchdog时间戳,以及时间戳更新间隔检测定时器 */td->status = HP_THREAD_ACTIVE;continue;case HP_THREAD_PARKED:__set_current_state(TASK_RUNNING);preempt_enable();if (ht->unpark)ht->unpark(td->cpu);td->status = HP_THREAD_ACTIVE;continue;}if (!ht->thread_should_run(td->cpu)) {preempt_enable_no_resched();schedule();} else {__set_current_state(TASK_RUNNING);preempt_enable();/* 更新当前 CPU 的 watchdog时间戳 */ht->thread_fn(td->cpu); /* kernel/watchdog.c: watchdog() */}}
}
static void watchdog_enable(unsigned int cpu)
{/* 启动时间戳更新间隔检测定时器 */hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);hrtimer->function = watchdog_timer_fn;hrtimer_start(hrtimer, ns_to_ktime(sample_period),HRTIMER_MODE_REL_PINNED);__touch_watchdog(); /* 初始 watchdog 的时间戳 */watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1); /* 设置为 RT 调度类的 SCHED_FIFO */
}
static void watchdog(unsigned int cpu)
{__this_cpu_write(soft_lockup_hrtimer_cnt,__this_cpu_read(hrtimer_interrupts));__touch_watchdog(); /* watchdog 线程负责时不时的更新当前CPU的watchdog时间戳 */
}
3.3.3 触发 soft lockup 问题报告
定时器到期后,进入 watchdog_timer_fn() ,触发可能的 soft lockup 问题报告:
/* watchdog kicker functions */
static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
{unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts); /* 读取当前CPU最近的更新的时间戳 */.../* kick the softlockup detector */wake_up_process(__this_cpu_read(softlockup_watchdog)); /* 唤醒当前CPU时间戳更新线程 *//* .. and repeat */hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));if (touch_ts == 0) { /* 休眠重启等类似情形下,时间戳复位为0 */...__touch_watchdog(); /* 重新初始化时间戳 */return HRTIMER_RESTART; /* 重启定时器 */}duration = is_softlockup(touch_ts); /* 上次更新的时间戳和当前时间戳的差值 */if (unlikely(duration)) { /* 时间戳差值大于设定的阈值 */.../* 报告 sotf lockup 问题 */pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",smp_processor_id(), duration,current->comm, task_pid_nr(current));__this_cpu_write(softlockup_task_ptr_saved, current);print_modules();print_irqtrace_events(current);if (regs)show_regs(regs);elsedump_stack();...add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);if (softlockup_panic)panic("softlockup: hung tasks");__this_cpu_write(soft_watchdog_warn, true);} else__this_cpu_write(soft_watchdog_warn, false);return HRTIMER_RESTART;
}
static int is_softlockup(unsigned long touch_ts)
{unsigned long now = get_timestamp();if ((watchdog_enabled & SOFT_WATCHDOG_ENABLED) && watchdog_thresh){/* Warn about unreasonable delays. *//* 更新时间戳的间隔超过了设定的阈值 */if (time_after(now, touch_ts + get_softlockup_thresh()))return now - touch_ts;}return 0;
}
4. softlock up 举例
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/delay.h>static struct task_struct *softlockup_task;static int softlockup_task_fn(void *ignored)
{int ret = 0;while (!kthread_should_stop()) {#if (defined(CONFIG_PREEMPT_NONE) || defined(CONFIG_PREEMPT_VOLUNTARY))asm("nop");#else /* CONFIG_PREEMPT */preempt_disable();mdelay(30 * 1000);preempt_enable();#endif}return ret;
}static int __init softlockup_task_demo_init(void)
{int ret = 0;softlockup_task = kthread_run(softlockup_task_fn, NULL, "softlockup_task");if (IS_ERR(softlockup_task)) {ret = PTR_ERR(softlockup_task);printk(KERN_ERR "%s: Failed to create kernel thread, ret = [%d]\n", __func__, ret);}printk(KERN_INFO "soft lockup task example module loaded.\n");return ret;
}static void __exit softlockup_task_demo_exit(void)
{if (softlockup_task) {kthread_stop(softlockup_task);softlockup_task = NULL;}printk(KERN_INFO "soft lockup task example module exited.\n");
}module_init(softlockup_task_demo_init);
module_exit(softlockup_task_demo_exit);MODULE_LICENSE("GPL");
这里包含配置编译的完整代码。编译测试模块:
#
# 配置
## 抢占模式 3 选一
CONFIG_PREEMPT_NONE=y
#CONFIG_PREEMPT_VOLUNTARY=y
#CONFIG_PREEMPT=yCONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_SAMPLE_SOFTLOCKUP=m
cd linux-4.14.132
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8 O=outputsudo mount rootfs.img temp
cd linux-4.14.132
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=output INSTALL_MOD_PATH=/path/to/temp modules_install
cd -
sudo umount temp
然后用QEMU启动系统,加载测试模块:
sudo qemu-system-arm \-M vexpress-a9 \-smp 4 \-m 512M \-kernel /path/to/zImage \-dtb /path/to/vexpress-v2p-ca9.dtb \-nographic \-append "root=/dev/mmcblk0 rw rootfstype=ext4 console=ttyAMA0" \-sd rootfs.img
# 当前位于 QEMU 模拟器系统特权模式下# modprobe softlockup_example
模块加载一段时间后,报 soft lockup BUG:
[ 157.356865] soft lockup task example module loaded.
[ 176.383362] INFO: rcu_sched self-detected stall on CPU
[ 176.384981] 1-...: (2113 ticks this GP) idle=a42/140000000000001/0 softirq=2326/2326 fqs=1019
[ 176.385513] (t=2100 jiffies g=903 c=902 q=636)
[ 176.387315] NMI backtrace for cpu 1
[ 176.387904] CPU: 1 PID: 939 Comm: softlockup_task Not tainted 4.14.132 #34
[ 176.387942] Hardware name: ARM-Versatile Express
[ 176.391912] [<8011149c>] (unwind_backtrace) from [<8010c330>] (show_stack+0x20/0x24)
[ 176.393289] [<8010c330>] (show_stack) from [<806ddfd8>] (dump_stack+0x8c/0xa0)
[ 176.393356] [<806ddfd8>] (dump_stack) from [<806e3dc4>] (nmi_cpu_backtrace+0xc0/0xc4)
[ 176.393417] [<806e3dc4>] (nmi_cpu_backtrace) from [<806e3eb0>] (nmi_trigger_cpumask_backtrace+0xe8/0x12c)
[ 176.393474] [<806e3eb0>] (nmi_trigger_cpumask_backtrace) from [<8010f490>] (arch_trigger_cpumask_backtrace+0x20/0x24)
[ 176.393534] [<8010f490>] (arch_trigger_cpumask_backtrace) from [<80182ea0>] (rcu_dump_cpu_stacks+0xac/0xd8)
[ 176.393672] [<80182ea0>] (rcu_dump_cpu_stacks) from [<80182478>] (rcu_check_callbacks+0x7f8/0x9f8)
[ 176.393725] [<80182478>] (rcu_check_callbacks) from [<80187f84>] (update_process_times+0x44/0x6c)
[ 176.393775] [<80187f84>] (update_process_times) from [<80197144>] (tick_periodic+0x4c/0xcc)
[ 176.393828] [<80197144>] (tick_periodic) from [<80197368>] (tick_handle_periodic+0x38/0x98)
[ 176.393877] [<80197368>] (tick_handle_periodic) from [<8010ffe4>] (twd_handler+0x40/0x50)
[ 176.393924] [<8010ffe4>] (twd_handler) from [<80172128>] (handle_percpu_devid_irq+0x98/0x24c)
[ 176.393979] [<80172128>] (handle_percpu_devid_irq) from [<8016c728>] (generic_handle_irq+0x34/0x44)
[ 176.394031] [<8016c728>] (generic_handle_irq) from [<8016cd3c>] (__handle_domain_irq+0x6c/0xc4)
[ 176.394125] [<8016cd3c>] (__handle_domain_irq) from [<80101508>] (gic_handle_irq+0x5c/0xa0)
[ 176.394166] [<80101508>] (gic_handle_irq) from [<8010d10c>] (__irq_svc+0x6c/0x90)
[ 176.394240] Exception stack(0x9e90df18 to 0x9e90df60)
[ 176.394533] df00: 00000000 9e983bc0
[ 176.394835] df20: 00000000 9e983bc0 9e983bc0 00000000 9f5fc940 9e90c000 00000000 9e983bdc
[ 176.394945] df40: 9e8fdd30 9e90df74 9e90df68 9e90df68 7f000020 7f000020 00000013 ffffffff
[ 176.396350] [<8010d10c>] (__irq_svc) from [<7f000020>] (softlockup_task_fn+0x20/0x30 [softlockup_example])
[ 176.396667] [<7f000020>] (softlockup_task_fn [softlockup_example]) from [<80143ae0>] (kthread+0x144/0x174)
[ 176.396718] [<80143ae0>] (kthread) from [<80107ee8>] (ret_from_fork+0x14/0x2c)
[ 204.214887] watchdog: BUG: soft lockup - CPU#1 stuck for 23s! [softlockup_task:939]
[ 204.215332] Modules linked in: softlockup_example
[ 204.215593] CPU: 1 PID: 939 Comm: softlockup_task Not tainted 4.14.132 #34
[ 204.215604] Hardware name: ARM-Versatile Express
[ 204.215648] task: 9f700c00 task.stack: 9e90c000
[ 204.215701] PC is at kthread_should_stop+0x30/0x54
[ 204.215736] LR is at softlockup_task_fn+0x20/0x30 [softlockup_example]
[ 204.215755] pc : [<80143524>] lr : [<7f000020>] psr: 00000013
[ 204.215770] sp : 9e90df50 ip : 9e90df68 fp : 9e90df64
[ 204.215785] r10: 9e8fdd30 r9 : 9e983bdc r8 : 00000000
[ 204.215804] r7 : 9e90c000 r6 : 9f5fc940 r5 : 00000000 r4 : 9f700c00
[ 204.215821] r3 : 00208040 r2 : 00000000 r1 : 9e983bc0 r0 : 00000000
[ 204.215875] Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 204.215899] Control: 10c5387d Table: 7e92806a DAC: 00000051
[ 204.215927] CPU: 1 PID: 939 Comm: softlockup_task Not tainted 4.14.132 #34
[ 204.215936] Hardware name: ARM-Versatile Express
[ 204.215979] [<8011149c>] (unwind_backtrace) from [<8010c330>] (show_stack+0x20/0x24)
[ 204.216011] [<8010c330>] (show_stack) from [<806ddfd8>] (dump_stack+0x8c/0xa0)
[ 204.216039] [<806ddfd8>] (dump_stack) from [<80108acc>] (show_regs+0x1c/0x20)
[ 204.216067] [<80108acc>] (show_regs) from [<801b5f08>] (watchdog_timer_fn+0x248/0x2c0)
[ 204.216095] [<801b5f08>] (watchdog_timer_fn) from [<80188f48>] (hrtimer_run_queues+0x1b8/0x370)
[ 204.216147] [<80188f48>] (hrtimer_run_queues) from [<80187f14>] (run_local_timers+0x24/0x50)
[ 204.216182] [<80187f14>] (run_local_timers) from [<80187f7c>] (update_process_times+0x3c/0x6c)
[ 204.216207] [<80187f7c>] (update_process_times) from [<80197144>] (tick_periodic+0x4c/0xcc)
[ 204.216232] [<80197144>] (tick_periodic) from [<80197368>] (tick_handle_periodic+0x38/0x98)
[ 204.216256] [<80197368>] (tick_handle_periodic) from [<8010ffe4>] (twd_handler+0x40/0x50)
[ 204.216282] [<8010ffe4>] (twd_handler) from [<80172128>] (handle_percpu_devid_irq+0x98/0x24c)
[ 204.216312] [<80172128>] (handle_percpu_devid_irq) from [<8016c728>] (generic_handle_irq+0x34/0x44)
[ 204.216338] [<8016c728>] (generic_handle_irq) from [<8016cd3c>] (__handle_domain_irq+0x6c/0xc4)
[ 204.216363] [<8016cd3c>] (__handle_domain_irq) from [<80101508>] (gic_handle_irq+0x5c/0xa0)
[ 204.216385] [<80101508>] (gic_handle_irq) from [<8010d10c>] (__irq_svc+0x6c/0x90)
[ 204.216399] Exception stack(0x9e90df00 to 0x9e90df48)
[ 204.216511] df00: 00000000 9e983bc0 00000000 00208040 9f700c00 00000000 9f5fc940 9e90c000
[ 204.216617] df20: 00000000 9e983bdc 9e8fdd30 9e90df64 9e90df68 9e90df50 7f000020 80143524
[ 204.216657] df40: 00000013 ffffffff
[ 204.216697] [<8010d10c>] (__irq_svc) from [<80143524>] (kthread_should_stop+0x30/0x54)
[ 204.216730] [<80143524>] (kthread_should_stop) from [<7f000020>] (softlockup_task_fn+0x20/0x30 [softlockup_example])
[ 204.216766] [<7f000020>] (softlockup_task_fn [softlockup_example]) from [<80143ae0>] (kthread+0x144/0x174)
[ 204.216791] [<80143ae0>] (kthread) from [<80107ee8>] (ret_from_fork+0x14/0x2c)
从上面可以看到,soft lockup 机制是依赖于中断的:当前 CPU 被占住无法调度的情形下,只有中断才能打断它,而用于检测的定时器接口,正是在中断上下文下执行。
5. soft lockup 用户空间接口
/proc/sys/kernel/soft_watchdog # 是否启用 softlockup 功能
/proc/sys/kernel/softlockup_panic # lockup是否导致kernel panic
/proc/sys/kernel/softlockup_all_cpu_backtrace # 是否不只输出lockup CPU调用栈,还输出其它CPU调用栈
/proc/sys/kernel/watchdog_thresh # softlockup 触发时间阈值
/proc/sys/kernel/watchdog_cpumask # 启用 softlockup 检测的CPU掩码
相关文章:
Linux:soft lockup 检测机制
1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. 分析背景 本文分析基于 linux-4.14.132 内核代码分析,运行环境 Ubuntu 16.04.4 LTS QEMU ARM vexpress-a9 ,rootfs 基…...
天线理论知识4——非频变天线
目录 简介自补结构巴比涅原理天线的描述常见的非频变天线简介 所谓的非频变天线指的是天线的参数几乎不随着频率的改变而发生变化。 自补结构 天线的自补结构指的是:由无限大且无厚度的理想导电区域的自由空间中的非导电区域放置一起的结构称为自补结构。包含金属部分和非金…...
基础架构组件选型及服务化
常见的分布式基础架构组件 分布式服务化框架,业界开源产品比如 Dubbo、Spring Cloud 这样的框架;分布式缓存及框架,业界如 Redis、Memcached,框架如 Codis 和 Redis Cluster;数据库及分布式数据库框架,这两…...
leetcode-每日一题-1247(中等,数学逻辑)
这道题当理解清了意思之后,只要是s1和s2的某位置的字母一样时我们就可以忽视比如s1"xxxxxxyyyy"; 就可以看成s1"xxxyyyy";s2"xxxyyyxxxx"; s2"yyyxxxx";其次就是只有当x和y位置差异产生的数量同奇偶的时候才可以构成相等字…...
前端面试题 —— 计算机网络(一)
目录 一、常见的HTTP请求头和响应头 二、HTTP状态码304是多好还是少好? 三、OPTIONS请求方法及使用场景 四、对keep-alive的理解 五、HTTP协议的优点和缺点 六、URL有哪些组成部分? 七、HTTPS通信(握手)过程 八、HTTPS的特…...
分布式-分布式缓存笔记
分布式系统缓存 缓存分类 前端缓存 前端缓存包括页面和浏览器缓存,如果是 App,那么在 App 端也会有缓存。当你打开商品详情页,除了首次打开以外,后面重复刷新时,页面上加载的信息来自多种缓存。 页面缓存属于客户端…...
【反序列化漏洞-01】为什么要序列化
为什么要序列化百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis,与数组类似)。以后,可以通过…...
用c语言模拟实现常用字符串函数
目录 一.常用字符串函数介绍 1.strlen 2. strcpy 3.strcmp 4.strcat 5.strstr 二.模拟实现常用字符串函数 1.strlen 2.strcpy 3.strcmp 4.strcat 5.strstr 一.常用字符串函数介绍 1.strlen 字符串strlen是用来求字符串长度的,我们可以打开cpp网站查看有关…...
在 Flutter 中使用 webview_flutter 4.0 | 基础用法与事件处理
大家好,我是 17。 Flutter WebView 一共写了四篇文章 在 Flutter 中使用 webview_flutter 4.0 | 基础用法与事件处理在 Flutter 中使用 webview_flutter 4.0 | js 交互Flutter WebView 性能优化,让 h5 像原生页面一样优秀,已入选 掘金一周 …...
JavaWeb--Servlet
Servlet1 简介2 快速入门3 执行流程4 生命周期5 方法介绍6 体系结构7 urlPattern配置8 XML配置目标: 理解Servlet的执行流程和生命周期掌握Servlet的使用和相关配置 1 简介 Servlet是JavaWeb最为核心的内容,它是Java提供的一门动态web资源开发技术。 使…...
Linux启动过程
theme: channing-cyan 两种启动方式 传统启动方式(LEGACYMBR) 指传统BIOS启动方式,存在一些不足:比如最大只支持2TB磁盘,磁盘最多四个分区,且不支持图形操作 UEFIGPT方式 是新式的启动方式,…...
面试资料整理——C++
C/C难题的高赞回答「中文版」 https://mp.weixin.qq.com/s/KBEnrRVb1T6LfwHgaB4jiQ C/C难题的高赞回答「中文版」,帮你整理好了 https://mp.weixin.qq.com/s/o9MdENiasolVT-Fllag2_Q C语言与C面试知识总结 https://mp.weixin.qq.com/s/MGSoPqPv_OzyWBS5ZdnZgw 程…...
【ArcGIS Pro二次开发】(9):GeoProcessing工具和自定义工具的调用
ArcGIS Pro自带了1000种以上的GeoProcessing工具,几乎可以实现所有你想要做的事。 ArcGIS Pro的二次开发并不需要我们从底层做起,很多功能只要学会调用工具并组合使用,就完全可以实现。 下面介绍如何调用系统自带的GeoProcessing工具&#x…...
皕杰报表斜线单元格、图表里或导出pdf的中文显示小方块解决方案
在皕杰报表中,如果含有斜线的单元格、统计图的报表、或导出pdf时,汉字变成小方框,这往往是服务器端操作系统的中文安装包没有装全,导致报表里用到的字体在服务器端的操作系统里找不到,因此成了小方块。因为斜线单元格里…...
python读写hdfs文件的实用解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…...
RK3399+FPGA+MIPI 方案细节之subLVDS to MIPI处理
#CROSSLINK系列 #CROSSLINK vs XO3L 总的来说XO3L的灵活性更强,更近似于一片通用的CPLD;CROSSLINK专用性更强。 针对subLVDS转换到MIPI的需求,CROSSLINK比较有优势,因为集成度更高,所以稳定性也更高。 #要点 #crossl…...
Vue组件是怎样挂载的
我们先来关注一下$mount是实现什么功能的吧: 我们打开源码路径core/instance/init.js: export function initMixin (Vue: Class<Component>) {......initLifecycle(vm)// 事件监听初始化initEvents(vm)initRender(vm)callHook(vm, beforeCreate)initInject…...
gcc: 编译选项:-fdelete-null-pointer-checks、-fno-delete-null-pointer-checks
文章目录 说明实例:Linux 里的使用chatGPT说明 这个说明写的有些理解不了,可能还是不太理解(有未知的东西在里面?)。但是从这个编译选项的命名上来看还是非常明确,就是删除不必要的空指针检查。使用时要小心了,这个优化超出了编译的界限! -fdelete-null-pointer-check…...
周赛334(前缀和、贪心+双指针、Dijkstra求最短路径、二分答案)
文章目录[6369. 左右元素和的差值](https://leetcode.cn/problems/left-and-right-sum-differences/)前缀和[6368. 找出字符串的可整除数组](https://leetcode.cn/problems/find-the-divisibility-array-of-a-string/)超长整数如何取余?[6367. 求出最多标记下标](ht…...
imx6ull——I2C驱动
I2C基本介绍 SCL 为高电平,SDA 出现下降沿:起始位 SCL 位高电平,SDA出现上升沿:停止位 主机——从机地址(ack)——寄存器地址(ack)——数据(ack) 重点:先是写,…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
