当前位置: 首页 > news >正文

c/c++实现有栈协程

有栈协程

有栈协程通过切换执行上下文实现,核心是切换栈寄存器和跳转ip代码地址,同时需要保存切换当前编译器ABI规定的 非易失寄存器

System V AMD64 ABI 和 MSVC x64 ABI 的非易失性寄存器RBX、RBP、RSP、R12、R13、R14、R15
XMM6-XMM15RDI、RSI、仅MSVC

MSVCGCC多了两个RDI、RSI,这些寄存器在切换时是必须要保存的。更多详情参考官方文档。

MSVC x64 ABI

切换核心汇编如下

linux amd 64extern "C" __attribute__((sysv_abi, naked, noinline)) void
switch_jmp(context_amd64 *save_, context_amd64 *jmp_);.text
.globl switch_jmpswitch_jmp:// rdi = save_, rsi = jmp_// 保存上下文到save_movq %rbx, 0x000(%rdi)    // RBXmovq %rbp, 0x008(%rdi)    // RBPmovq %rsp, 0x010(%rdi)    // RSPmovq %r12, 0x018(%rdi)    // R12movq %r13, 0x020(%rdi)    // R13movq %r14, 0x028(%rdi)    // R14movq %r15, 0x030(%rdi)    // R15#ifdef SAVE_FLOATmovaps %xmm6, 0x040(%rdi)   // XMM6movaps %xmm7, 0x050(%rdi)   // XMM7movaps %xmm8, 0x060(%rdi)   // XMM8movaps %xmm9, 0x070(%rdi)   // XMM9movaps %xmm10, 0x080(%rdi)  // XMM10movaps %xmm11, 0x090(%rdi)  // XMM11movaps %xmm12, 0x0A0(%rdi)  // XMM12movaps %xmm13, 0x0B0(%rdi)  // XMM13movaps %xmm14, 0x0C0(%rdi)  // XMM14movaps %xmm15, 0x0D0(%rdi)  // XMM15
#endif// 从jmp_恢复上下文movq 0x000(%rsi), %rbx  // RBXmovq 0x008(%rsi), %rbp  // RBPmovq 0x010(%rsi), %rsp  // RSPmovq 0x018(%rsi), %r12  // R12movq 0x020(%rsi), %r13  // R13movq 0x028(%rsi), %r14  // R14movq 0x030(%rsi), %r15  // R15
#ifdef SAVE_FLOATmovaps 0x040(%rsi), %xmm6movaps 0x050(%rsi), %xmm7movaps 0x060(%rsi), %xmm8movaps 0x070(%rsi), %xmm9movaps 0x080(%rsi), %xmm10movaps 0x090(%rsi), %xmm11movaps 0x0A0(%rsi), %xmm12movaps 0x0B0(%rsi), %xmm13movaps 0x0C0(%rsi), %xmm14movaps 0x0D0(%rsi), %xmm15
#endifret

c++异常在windows下的有栈协程里失效

实际情况可能很复杂,msvc c++实现在SEH(结构化异常处理)机制之上,如上的上下文切换在windows会让协程的c++异常无法被catch拦截,会直接崩溃。

借鉴了boost.context的实现,hack了线程gs:[030h] NT_TIB结构,切换了栈base地址,msvc c++异常就可以被拦截 成功运行,但MINGW下异常还是无法被正常catch!!

    ; load NT_TIBmov  r10,  gs:[030h]mov  rax, [r10+01478h]mov  [rcx+048h], raxmov  rax, [r10+010h]mov  [rcx+050h], raxmov  rax,  [r10+08h]mov  [rcx+058h], raxmov  r10,  gs:[030h]mov  rax, [rdx+048h]mov  [r10+01478h], raxmov  rax, [rdx+050h]mov  [r10+010h], raxmov  rax, [rdx+058h]mov  [r10+08h], rax

关于TLS,不推荐自己hack gs fs寄存器实现TLS,在原有TLS上封装协程的TLS就好。

关于栈切换保存在哪儿?有的实现是直接在当前栈压入,但这种实现是需要返回值的。还是采取了非压入栈的,在独立的地方存储上下文。

封装相关:协程挂起时,应该跳出到调度器,保持干净的栈,所以挂起时时返回到调度器的resume后。

有栈协程实现demo,全部源码:

//allocate.h
#include <cstddef>
#include <cassert>#ifdef _WIN32
#include <Windows.h>
std::size_t page_size() {SYSTEM_INFO si;::GetSystemInfo(&si);return static_cast<std::size_t>(si.dwPageSize);
}
void *allocate_stack(size_t size_, size_t &out_size) {size_t page_size_ = page_size();const std::size_t pages = (size_ + page_size_ - 1) / page_size_;const std::size_t size__ = (pages + 1) * page_size_;out_size = size__;void *vp = ::VirtualAlloc(0, size__, MEM_COMMIT, PAGE_READWRITE);assert(vp != nullptr && "VirtualAlloc NULL");DWORD old_options;// 增加一个PAGE_GUARD保护页,拦截栈溢出const BOOL result = ::VirtualProtect(vp, page_size_, PAGE_READWRITE | PAGE_GUARD, &old_options);assert(FALSE != result && "VirtualProtect false");return vp;
}void free_stack(void *ptr, size_t size) { ::VirtualFree(ptr, 0, MEM_RELEASE); }
#elif __linux__
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>std::size_t page_size() {return static_cast<std::size_t>(::sysconf(_SC_PAGESIZE));
}void *allocate_stack(size_t size_, size_t &out_size) {size_t page_size_ = page_size();const std::size_t pages = (size_ + page_size_ - 1) / page_size_;const std::size_t size__ = (pages + 1) * page_size_;out_size = size__;void *vp = ::mmap(0, size__, PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);assert(vp != nullptr && "::mmap return null!");const int result(::mprotect(vp, page_size_, PROT_NONE));assert(0 == result && "::mprotect faild!");return vp;
}
void free_stack(void *ptr, size_t size) { ::munmap(ptr, size); }#endif
//stackfull.cpp
#include <cassert>
#include <cstddef>
#include <iostream>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <memory>
#include <list>
#include <algorithm>
#include <atomic>
#include <string.h>#include "allocate.h"#if !(defined(__x86_64__) || defined(_M_X64) || defined(__amd64__) ||          \defined(__amd64))
#error "此程序仅支持 AMD64 (x86-64) 架构平台,不支持当前平台编译。"
#endifnamespace co {struct context_amd64;
#ifdef _WIN64
#if defined(_MSC_VER)
extern "C" __declspec(noinline) void switch_jmp(context_amd64 *save_,context_amd64 *jmp_);
#elif __MINGW64__
extern "C" __attribute__((ms_abi, naked, noinline)) void
switch_jmp(context_amd64 *save_, context_amd64 *jmp_);
#endif
#elif __linux__
extern "C" __attribute__((sysv_abi, naked, noinline)) void
switch_jmp(context_amd64 *save_, context_amd64 *jmp_);
#endif// System V AMD64 ABI 和 MSVC x64 ABI 的非易失性寄存器
// RDI、RSI、仅MSVC
// RBX、RBP、RSP、R12、R13、R14、R15
// XMM6-XMM15constexpr size_t rbp_index = 1;
constexpr size_t rsp_index = 2;
// xmm align 16
struct xmm_regs {uint64_t _1;uint64_t _2;
};
struct alignas(16) context_amd64 {uint64_t regs[7]{}; // RBX、RBP、RSP、R12、R13、R14、R15
#ifdef _WIN64uint64_t rdi_rsi[2]{}; // RDI、RSI、uint64_t tib_info[3];  // fc_dealloc  limit  base     windows tib
#elseuint64_t alignas__ = 0;//仅对齐
#endif // _WIN64_// cmakelist中启用SAVE_FLOAT
#ifdef SAVE_FLOATxmm_regs regs_xmm[10]{}; // XMM6-XMM15 它需要16对齐
#endif
};struct coroutine_base;
struct context_tls {context_amd64 break_{};struct coroutine_base *co_current_ = nullptr;
};constexpr size_t STACK_SIZE = 1024 * 1024 * 2;
thread_local context_tls switch_;void co_suspend();void debug_print(const char *action, const char *name) {std::cout << std::right << std::setfill('=');std::string action_;action_.append("[");action_.append(action);action_.append("]");std::cout << std::setw(15) << action_;std::cout << std::setw(10) << name << std::endl;
};struct coroutine_base {static void entry() noexcept {context_tls &tls_ = switch_;coroutine_base *this_ = tls_.co_current_;debug_print("start", this_->name());try {this_->invoke();} catch (...) {this_->except_ptr = std::current_exception();}this_->done_ = true;debug_print("end", this_->name());switch_jmp(&this_->context_,&tls_.break_); // 没有ret地址,不能继续必须跳转};public:void resume() {if (done_)return;context_tls &tls_ = switch_;tls_.co_current_ = this;debug_print("resume", this->name());switch_jmp(&tls_.break_, &this->context_);debug_print("suspend", this->name());}bool done() { return done_; }template <typename R> R get() {return std::move(*std::launder(static_cast<R *>(result())));}std::exception_ptr &except() { return except_ptr; }template <typename R> void set(R &&r) {using type = std::remove_reference_t<R>;*std::launder(static_cast<type *>(result())) = r;}template <typename RR> static void current_yield(RR &r) {context_tls &tls_ = switch_;tls_.co_current_->set(std::forward<RR>(r));co::co_suspend();}const char *name() { return name_.c_str(); }void set_name(const char *_name) { name_ = _name; }virtual ~coroutine_base() { free_stack(stack_m_, stack_size_); }protected:coroutine_base(size_t stack_size) {stack_m_ = (uint8_t *)allocate_stack(stack_size, stack_size_);stack_ = stack_m_ + stack_size_; // 逆行增长// 压入一个空地址 对齐16 重要 这是默认call的压栈stack_ = stack_ - sizeof(uintptr_t);// 压入entry,配合switch_jmpstack_ = stack_ - sizeof(uintptr_t);*static_cast<uintptr_t *>((void *)stack_) =(uintptr_t)&coroutine_base::entry;context_.regs[rsp_index] = (uintptr_t)(void *)stack_;context_.regs[rbp_index] = (uintptr_t)(void *)stack_;
#ifdef _WIN64//  c++ 异常 msvc windowscontext_.tib_info[0] = (uintptr_t)(stack_ - stack_size);context_.tib_info[1] = (uintptr_t)(stack_ - stack_size);context_.tib_info[2] = (uintptr_t)stack_;
#endif};virtual void invoke() = 0;virtual void *result() = 0;context_amd64 context_{};uint8_t *stack_m_ = nullptr;uint8_t *stack_ = nullptr;size_t stack_size_ = 0;std::atomic_bool done_ = false;std::exception_ptr except_ptr{};std::string name_;friend void co_suspend();
};void co_suspend() {context_tls &tls_ = switch_;coroutine_base *this_ = tls_.co_current_;switch_jmp(&this_->context_, &tls_.break_);
};template <typename R> struct result_storage {alignas(std::max_align_t) uint8_t ret_s[sizeof(R)]{};void *get_addr() { return static_cast<void *>(&this->ret_s[0]); }
};
template <> struct result_storage<void> {void *get_addr() {throw std::runtime_error("void null!");return nullptr;}
};template <typename R, typename... Args>
struct coroutine : public coroutine_base {public:template <typename F, typename... Args2>coroutine(F &&_func, Args2 &&..._args) noexcept: coroutine_base(STACK_SIZE), args_(std::forward<Args2>(_args)...) {coro_main_ = _func;}private:result_storage<R> ret{};std::tuple<Args...> args_{};std::function<R(Args...)> coro_main_;void invoke() override {if constexpr (std::is_void_v<R>) {std::apply(coro_main_, args_);} else {new (ret.get_addr()) R(std::apply(coro_main_, args_));}}void *result() override { return ret.get_addr(); }
};template <typename F, typename... Args>
co::coroutine_base *create_co(const char *name, F &&_func, Args &&..._args) {using R = std::invoke_result_t<F, Args...>;auto *ptr = new co::coroutine<R, Args...>(std::forward<F>(_func),std::forward<Args>(_args)...);ptr->set_name(name);return ptr;
};
} // namespace coint main() {std::cout << 1.132 << std::endl;using coro_unptr = std::unique_ptr<co::coroutine_base>;std::list<coro_unptr> task_;task_.emplace_back(co::create_co("co_1", []() {std::cout << "hello " << std::endl;co::co_suspend();std::cout << "world~" << std::endl;}));task_.emplace_back(co::create_co("co_2",[](int x) {int my_value = 123;int other = 200;other += 100;double f64 = 1.23;f64 = f64 + 2.222;co::co_suspend();double ret = (my_value + other + x) + f64;std::cout << "co_r value:" << ret << std::endl;return ret;},10000));while (task_.size() > 0) {for (auto &t : task_) {if (!t->done()) {t->resume();}}std::erase_if(task_, [](const auto &x) { return x->done(); });}coro_unptr generator_test(co::create_co("co_3",[](size_t x) -> size_t {for (size_t i = 0; i < x; i++) {co::coroutine_base::current_yield(i);}return 0;},10));while (true) {if (!generator_test->done()) {generator_test->resume();size_t v = generator_test->get<size_t>();std::cout << "generator:" << v << std::endl;} elsebreak;}coro_unptr throw_test(co::create_co("co_test", []() { throw std::runtime_error("error !!!"); }));try {throw_test->resume();if (throw_test->except())std::rethrow_exception(throw_test->except());} catch (const std::exception &e) {std::cout << "exception: " << e.what() << std::endl;}std::cout << "end####" << std::endl;return 0;
}
;win_msvc.asm
.codeswitch_jmp proc frame.endprolog;RCX save_,RDX jmp_;-----------保存到上下文到save_-------------mov [rcx + 000h], rbx   ; RBXmov [rcx + 008h], rbp   ; RBPmov [rcx + 010h], rsp   ; RSPmov [rcx + 018h], r12   ; R12mov [rcx + 020h], r13   ; R13mov [rcx + 028h], r14   ; R14mov [rcx + 030h], r15   ; R15mov [rcx + 038h], rdi   ; RDImov [rcx + 040h], rsi   ; RSI; load NT_TIBmov  r10,  gs:[030h]mov  rax, [r10+01478h]mov  [rcx+048h], raxmov  rax, [r10+010h]mov  [rcx+050h], raxmov  rax,  [r10+08h]mov  [rcx+058h], raxIFDEF SAVE_FLOATmovaps [rcx + 0060h], xmm6    ; XMM6movaps [rcx + 0070h], xmm7    ; XMM7movaps [rcx + 0080h], xmm8    ; XMM8movaps [rcx + 0090h], xmm9    ; XMM9movaps [rcx + 00A0h], xmm10   ; XMM10movaps [rcx + 00B0h], xmm11   ; XMM11movaps [rcx + 00C0h], xmm12   ; XMM12movaps [rcx + 00D0h], xmm13   ; XMM13movaps [rcx + 00E0h], xmm14   ; XMM14movaps [rcx + 00F0h], xmm15   ; XMM15
ENDIF;-----------从jmp_恢复上下文-------------; 恢复整数寄存器mov rbx, [rdx + 000h] ; RBXmov rbp, [rdx + 008h] ; RBPmov rsp, [rdx + 010h] ; RSPmov r12, [rdx + 018h] ; R12mov r13, [rdx + 020h] ; R13mov r14, [rdx + 028h] ; R14mov r15, [rdx + 030h] ; R15mov rdi, [rdx + 038h] ; RDImov rsi, [rdx + 040h] ; RSI; load NT_TIBmov  r10,  gs:[030h]mov  rax, [rdx+048h]mov  [r10+01478h], raxmov  rax, [rdx+050h]mov  [r10+010h], raxmov  rax, [rdx+058h]mov  [r10+08h], raxIFDEF SAVE_FLOATmovaps  xmm6,  [rdx+0060h]movaps  xmm7,  [rdx+0070h]movaps  xmm8,  [rdx+0080h]movaps  xmm9,  [rdx+0090h]movaps  xmm10, [rdx+00A0h]movaps  xmm11, [rdx+00B0h]movaps  xmm12, [rdx+00C0h]movaps  xmm13, [rdx+00D0h]movaps  xmm14, [rdx+00E0h]movaps  xmm15, [rdx+00F0h]
ENDIFretswitch_jmp endp
end    
//linux_gas.S
.text
.globl switch_jmpswitch_jmp:// rdi = save_, rsi = jmp_// 保存上下文到save_movq %rbx, 0x000(%rdi)    // RBXmovq %rbp, 0x008(%rdi)    // RBPmovq %rsp, 0x010(%rdi)    // RSPmovq %r12, 0x018(%rdi)    // R12movq %r13, 0x020(%rdi)    // R13movq %r14, 0x028(%rdi)    // R14movq %r15, 0x030(%rdi)    // R15#ifdef SAVE_FLOATmovaps %xmm6, 0x040(%rdi)   // XMM6movaps %xmm7, 0x050(%rdi)   // XMM7movaps %xmm8, 0x060(%rdi)   // XMM8movaps %xmm9, 0x070(%rdi)   // XMM9movaps %xmm10, 0x080(%rdi)  // XMM10movaps %xmm11, 0x090(%rdi)  // XMM11movaps %xmm12, 0x0A0(%rdi)  // XMM12movaps %xmm13, 0x0B0(%rdi)  // XMM13movaps %xmm14, 0x0C0(%rdi)  // XMM14movaps %xmm15, 0x0D0(%rdi)  // XMM15
#endif// 从jmp_恢复上下文movq 0x000(%rsi), %rbx  // RBXmovq 0x008(%rsi), %rbp  // RBPmovq 0x010(%rsi), %rsp  // RSPmovq 0x018(%rsi), %r12  // R12movq 0x020(%rsi), %r13  // R13movq 0x028(%rsi), %r14  // R14movq 0x030(%rsi), %r15  // R15
#ifdef SAVE_FLOATmovaps 0x040(%rsi), %xmm6movaps 0x050(%rsi), %xmm7movaps 0x060(%rsi), %xmm8movaps 0x070(%rsi), %xmm9movaps 0x080(%rsi), %xmm10movaps 0x090(%rsi), %xmm11movaps 0x0A0(%rsi), %xmm12movaps 0x0B0(%rsi), %xmm13movaps 0x0C0(%rsi), %xmm14movaps 0x0D0(%rsi), %xmm15
#endifret

cmake_minimum_required (VERSION 3.10)project ("stackfull")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)add_compile_definitions(SAVE_FLOAT)if (UNIX AND NOT APPLE)message(STATUS "Platform: Linux")enable_language(ASM)set(ASM_SOURCES linux_gas.S)
elseif (WIN32)if (MSVC)message(STATUS "Platform: Windows MSVC")enable_language(ASM_MASM)set(ASM_SOURCES win_msvc.asm)elseif (MINGW)message(STATUS "Platform: Windows MinGW")enable_language(ASM)set_source_files_properties(win_gas.S PROPERTIESCOMPILE_FLAGS "-x assembler-with-cpp"
)set(ASM_SOURCES win_gas.S)add_compile_options(-fexceptions)endif ()
else()message(FATAL_ERROR "Unsupported platform")
endif()add_executable (stackfull "stackfull.cpp" "allocate.h" ${ASM_SOURCES})

相关文章:

c/c++实现有栈协程

有栈协程 有栈协程通过切换执行上下文实现,核心是切换栈寄存器和跳转ip代码地址,同时需要保存切换当前编译器ABI规定的 非易失寄存器。 System V AMD64 ABI 和 MSVC x64 ABI 的非易失性寄存器RBX、RBP、RSP、R12、R13、R14、R15 XMM6-XMM15RDI、RSI、仅MSVCMSVC比GCC多了两个…...

Day17冒泡排序

package com.cc.array;import java.util.Arrays;public class ArrayDemo7 {public static void main(String[] args) {int [] a = {21,4,5,6,35,65,23,34,53,5};Arrays.sort(a);System.out.println(Arrays.toString(a));}//冒泡排序//1,比较数组中,两个相邻的元素,如果第一个…...

高阶 INTJ 5w4 整合到 8,是完整的过程,从研究到实用(豆包)

高阶INTJ 5w4整合到8的完整过程,是一个从认知重构、情感突破到行为落地的系统性进化,需要经历理论奠基→动态转化→实践固化三个阶段。以下结合九型人格整合机制、INTJ发展规律及5w4的特质矛盾,展开从研究到实用的全链条解析: 一、理论奠基:理解整合的底层逻辑(研究阶段)…...

几B大模型的空间存储大小

1. 前言砚上三五笔,落墨鹧鸪啼关于大模型总是会出现几B,然后想知道他们的存储空间大小分别是多少。还有描述一些显卡的TFLOPS是怎么计算的。这里做一个简单的记录。 如有不对,欢迎评论区指正! 2. 正文 2.1 精度类型 包括FP64:64位双精度浮点型 8字节 double FP32:32位单…...

hbase安装与配置

解压文件改名配置环境变量配置文件(忘记截图了,问ai即可) cd $HBASE_HOME/conf hbase-env.sh,hbase-site.xml, regionservers 启动前准备 hdfs dfs -mkdir -p /hbase hdfs dfs -chown hadoop:hadoop /hbase 如果各种配置都配好了却一直有问题(我是报server is not runnin…...

发喷山火(volcano)+CF2119F Volcanic Eruptions 解题报告

发喷山火 神题 先来初步挖掘一下这个走路过程的性质:初始时 \(S=1\),且 \(S\le 0\) 就死了,所以在没有走到 \((1,1)\) 之前,只能走 \((1,-1)\) 的边。 由于你和岩浆走路速度相同,所以一旦路径中你已经触碰到岩浆,那么你无论如何都逃不出去了,所以触碰过岩浆等价于最后停…...

matlab免费下载安装激活教程(附安装包下载)MATLAB R2025a超详细下载安装教程

MATLAB R2025a是2025年工科必备的工程计算软件,不管是大学生做课程设计、研究生写论文,还是工程师搞项目研发,用它处理矩阵运算、建模仿真都特别方便。新版本运算速度比上一代快35%,还新增了新能源、自动驾驶专用工具箱,功能更全。很多人觉得安装难,其实分三步就能搞定,…...

Spring Boot + flowable 完美结合,快速实现工作流 - 教程

Spring Boot + flowable 完美结合,快速实现工作流 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", m…...

Pyfluent 执行Meshing工作流

1. 部署安装pyfluent Pyfluent支持Fluent 2022R2或更高版本,PyFluent支持Python 3.10~3.13版本,点击 此处 即可下载。 安装核心依赖需使用pip命令,如若详细了解该命令的使用,详见 此处 pip install ansys-fluent-core pip install pyfluent //如有需要可进一步安装 pip ins…...

EF Core 与 MySQL:日志和调试详解

本文将详细讲解EF Core与MySQL的日志和调试,分为三个部分:EF Core日志配置、MySQL日志查看以及使用调试工具分析查询性能。 1. 配置 EF Core 日志 基本日志配置// 在DbContext配置中启用日志记录 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuil…...

使用镜像源解决github拉取代码问题 - GD

命令行输入以下语句: git config --global url."https://gitclone.com/github.com/".insteadOf "https://github.com/" 取消设置: git config --global --unset url."https://gitclone.com/github.com/".insteadOf 参考:[https://www.cnblogs…...

日记

redis的运行指令 redis-server.exe redis.windows.conf 开始大创的实施...

主机连接虚拟机和hbase的命令

telnet+ip+端口号 主机hbase...

类和面向对象

概述:语言特性有二,其一为既面向过程又面向对象,其二为用类和对象表示数据和操作数据的,c++将操作和数据汇聚成类和对象何为对象?即世间的一切事物。假如一个对象为feijib,则可以说这个为类feijib,难道类是对象的别名?按下不表。类具有一些属性和方法,即feijjib是硅胶…...

PHP转Go系列 | PHP8 这些新函数让你眼前一亮

说实话,PHP8 中的这三个新函数让字符串检查,变得非常直观,就像让代码说人话一样。这对我们程序员来说是一件大好事,提升可读性,减少 Bug 量,升级到 PHP8 之后,再也不用维护类似的屎山代码了。大家好,我是码农先森。 在 PHP8 之前做字符串相关的检查操作比较麻烦,可读性…...

代码随想录算法训练营第二天 |209.长度最小的子数组,59. 螺旋矩阵 II

209.长度最小的子数组 思路:快慢指针的思想,当快指针一直移动的时候,那么数列一定是递增的,且我们要求的是连续的数组,所以我们其实可以一次性用一个for就给全部遍历完成。当我们这个区间的值大于了target,我们就可以开始移动我们的慢指针了,直到我们的慢指针到达快指针…...

mac更新or安装homebrew失败

错误信息:fatal: unable to access https://github.com/Homebrew/brew/: LibreSSL SSL_read: error:02FFF03C:system library:func(4095):Operation timed out, errno 60可以用命令:/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew…...

Typescript中闭包的原理 - 教程

Typescript中闭包的原理 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font…...

CF2048H Kevin and Strange Operation

操作的自由度很大,打表可以发现限制操作的位置只增不减也是对的。 考虑怎么判断一个串 \(t\) 是否合法。 观察到对于一个位置 \(i\) 满足 \(s_i=0\),想要通过操作使 \(s_i\) 变为 \(1\),只需要 \(>i\) 的位置删掉了 \(\ge c_i\) 个数。其中 \(c_i\) 为 \(>i\) 的第一个…...

Hadoop本地库加载问题分析与解决方案

主要问题分析 ​​本地库加载警告​​: WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 这表明Hadoop无法正确加载本地优化库,将回退到纯Java实现,性能可能受影响 ​​栈保护警告​​…...

GO基础总结

环境搭建 基本语法 参见:https://www.cnblogs.com/vonlinee/p/19005628 工具链...

Visual Studio 离线安装0x80131509

Visual Studio 2026在本月发布了,它最大的特点是集成了GitHub Copilot,内置AI编程,空了要尝尝鲜(使用过Visual Studio Code的Copilot,还是挺有用的)。目前,VS2022很少使用,像VS2012一样被跳过,主要使用VS2019,甚至有时需要VS2010编译。分享一个离线安装Visual Studio…...

Oracle备份恢复:backup as copy保留文件名不变化,只更改路径名

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。Oracle备份恢复:backup as copy保留文件名不变化,只更改路径名 有些时…...

读书笔记:数据库中的预连接神器:位图连接索引

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本文为个人学习《Expert Oracle Database Architecture Techniques and…...

故障处理:CRS无法随操作系统自动启动故障案例分享

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。今天分享一个前几天网友遇到的集群环境中CRS无法随操作系统自动启动,但…...

02020401 EF Core基础01-EF Core简介和开发环境搭建、实体类、配置类、继承DbContex的类、Migration包的使用

02020401 EF Core基础01-EF Core简介和开发环境搭建、实体类、配置类、继承DbContex的类、Migration包的使用 1. EF Core简介(视频3-1)本课程需要你有数据库、SQL等基础知识。关系数据库:MySql、SQL Server、Oracle等。表(字段/列),表与表之间通过外键关联。对象数据库:…...

专用通路方式

-取址周期 1.从pc取址到mar (pc)->mar 此时c0有效 2.把刚才的值交给内存 (mar)->内存 c1 3.让内存读取mar中保存的值 1->r 4.让mdr获取内存刚刚读取的mar中保存的代码值 MEM(MAR)->MDR C2 5.再让IR(指令寄存器)获取MDR中的值 (MDR)->IR C3 6.(PC)+1=PC 7.最…...

typeof()

C# 中的 typeof() 是啥?一句话讲清楚:typeof() 就是“问编译器:这个类型长啥样?”它不是运行时去查对象,而是编译时就确定你写的那个“类名、接口名、结构名”到底是谁,然后返回一个叫 Type 的对象,这个对象里装满了这个类型的“身份证信息”。举个接地气的例子: 你写:…...

【未完成】2025.9 做题记录

CF1310C CF616F CF1065G CF1536F. Omkar and Akmar *2600 题意 Alice 和 Bob 在一个 \(n\) 个格子的环上玩游戏,环上的格子编号为 \(1\sim n\)。 每一轮中,玩家可选择一个空格子填入字母 A 或 B,同时要求不能存在两个相邻的格子内的字母相同。若没有合法操作,则游戏结束,当…...

2025.8 做题记录

P4064 [JXOI2017] 加法 蓝 题意 可怜有一个长度为 \(n\) 的正整数序列 \(A\),但是她觉得 \(A\) 中的数字太小了,这让她很不开心。 于是她选择了 \(m\) 个区间 \([l_i,r_i]\) 和两个正整数 \(a,k\)。她打算从这 \(m\) 个区间里选出恰好 \(k\) 个区间,并对每个区间执行一次区间…...

关于 “Thinking Machines Lab首次发长文” 的一些知识的学习和补充

1. 前言砚上三五笔,落墨鹧鸪啼原文链接: https://thinkingmachines.ai/ 相关分析链接:https://www.gongjiyun.com/blog/2025/9/fu1xw1spci9vnokjipecs9y9nzn/最近看到一篇名为《击败 LLM 推理中的非确定性:从“玄学”到可控》的文章,这里将一些知识盲区简单记录下。 如有不…...

CF1630F 题解 | 网络流

传送门 题意 给你一个长度为 \(n\) 的序列 \(a\),构建一个无向图:若 \(a_i | a_j\),则在 \(i\) 和 \(j\) 中连边。 求最少删除多少个点,才能使得剩下的图是二分图。 思路 首先,我们知道倍数关系是一个偏序关系,即 \(a_i | a_j, a_j | a_k \rightarrow a_i | a_k\)。 所以…...

攻防世界-secret-galaxy-300 - xxx

先查壳,无壳,32位程序先运行一下这个exe程序,发现闪一下就消失了,也没有什么提示字符串可查看。打算先去od里面运行看看 打开后没看到什么,查看字符串一时间也没看出什么,不过这个task函数倒是让控制台输出一堆奇怪的东西说实话看了之后有点懵,不过没关系,既然OD没什么…...

实用指南:LeetCode 面试经典 150_哈希表_单词规律(41_290_C++_简单)

实用指南:LeetCode 面试经典 150_哈希表_单词规律(41_290_C++_简单)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier …...

数据库

数据库操作DDL 创建 create database 数据库名查询 show databases ; show database like 数据库名;修改 alter database 数据库名 set 字段名 类型 约束;删除 drop database 数据库名;使用 use 数据库名;数据库表操作DDL 创建 create table 表名(字段 类型 索引);查看表…...

代码随想录算法训练营第二天 | leetcode 209

长度最小的子数组(没做出来) 题目要求:寻找一个数组中满足大于等于目标要求的最小子数组 解题思路:返回结果可能是不存在,所以需要定义一个合适的初始值,可以使用java的最大数Integer.MAX_VALUE,然后使用滑动窗口寻找满足条件的子数组,这时还需要对之前的数进行减去,避…...

mpv硬件解码

mpv --hwdec=yes --vo=vappi 3e559881c836c30321894b20ae102c4e.mp4...

2025.9.78——卷6-8选择

卷6选择 大O表示法 大O表示法由​​德国数学家保罗巴赫曼(Paul Bachman)提出,用于表示算法的最坏情况下时间复杂度 Θ表示法 Θ表示法通常归功于​​计算机科学家Donald Knuth​​等人,用于描述算法的平均时间复杂度 ST表 预处理时间复杂度O(NlogN),查询O(logN) AVL树 一种…...

关于pytorch的读书报告

PyTorch 读书报告 一、引言 PyTorch 是由 Facebook(现 Meta)人工智能研究实验室开发的一款开源机器学习框架,自 2016 年推出以来,凭借其动态计算图特性、简洁直观的 API 设计以及强大的生态系统,迅速成为学术界和工业界深度学习研究与应用的主流工具之一。本报告将围绕 Py…...

Emacs 折腾日记(三十)——打造C++ IDE 续

上一篇博客中,我完成了C++ IDE初步工作,包括代码的高亮、折叠、跳转以及补全等工作。但是作为IDE来说功能还有点不够,就我个人而言作为IDE来说它还需要具备一键编译运行和调试功能。这篇文章就来记录我是如何实现上述功能的 编译运行 我使用的演示项目比较简单,它的文件结构…...

数据结构 项目一

一:数据结构的基本概念 数据结构----研究数据的特性及数据之间存在的关系 算法+数据结构=程序。其中数据结构是指数据逻辑结构和物理结构,算法是对数据运算的描述。 用计算机解决一个具体问题时,首先从具体问题中抽象出一个适当的数学模型,然后设计一个能解此数学模型的算法…...

好烦

我不行了,一做初赛题就有一种莫名其妙的烦躁,根本就写不进去,一点都冷静不下来...

【STL库】哈希封装 unordered_map/unordered_set - 教程

【STL库】哈希封装 unordered_map/unordered_set - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", mon…...

用 Go 语言与 Tesseract OCR 识别英文数字验证码

一、安装与配置 安装 Tesseract OCR 你需要先安装 Tesseract OCR 引擎。具体步骤如下: Ubuntu: 更多内容访问ttocr.com或联系1436423940 sudo apt-get update sudo apt-get install tesseract-ocr macOS: brew install tesseract Windows: 可以从 Tesseract GitHub 下载并安装…...

FreeRTOS和LVGL组合使用教程

前言 关于这两者组合使用的教程,网上可以说是各种方法都有,移植的时候我也有遇到各种问题,在此处记录一下解决过程 问题 栈空间的分配问题 FreeRTOS和LVGL的栈分配都尽量多一点,不然后面的任务可能创建失败 lvgl心跳的问题 网上也有很多方法FreeRTOS钩子函数 单开一个定时器…...

Pip换源

清华大学源 比较全,但是没有torch pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple南京大学源 有torch但是很多包没有,建议用来安装torch pip3 install torch torchvision torchaudio --index-url https://mirrors.nju.edu.cn/pytorch…...

7zip压缩解压缩-测试CPU性能

前言全局说明在B站刷大佬视频的时候,看到UP在Debign linux 上用7z测试CPU性能,惊讶,7z还有这功能。 赶快打开手边的电脑,看看 Windows 上的 7z 有没有这功能,一用,果然有这个功能。 以前想知道CPU性能就只能装些 XX大师,现在有了这个小巧的工具,知道参考数值就很方便了…...

高数

1 求 \(\lim_{n\to\infty}\left(1-\frac 1n\right)^{n^2}\) 解: 首先证明 \(\lim_{n\to\infty}\left(1-\frac 1n\right)^{n}=e^{-1}\)。 \[\begin{align*} \lim_{n\to\infty}\left(1-\frac 1n\right)^{n} &=\lim_{n\to\infty}\left[\left(1-\frac 1n\right)^{(n-1)}\right…...

P5666 [CSP-S2019] 树的重心

分为 \(x \ne rt\) 和 \(x = rt\) 两种情况计算. 对于第一种情况,不难发现我们合法的裁减下来的连通块大小是在一个区间范围之内的,于是 DFS 时用一棵树状数组修改即可(因为这个大小可能是子树大小可能是子树外大小,这取决于你一条祖先链有哪些点),但子树内的 siz 可能会被记入…...

Java运行机制

Java 程序运行机制 编译型(compile) 解释型 程序运行机制 ![机制图](C:\Users\asus\Desktop\图集\屏幕截图 2025-09-18 204707.png)...