线程池中的意外发现
本来我在认真学习bind和function的区别 1. std::bind 的作用std::bind 的作用是将函数和其参数绑定在一起,返回一个可调用对象。当你调用这个对象时,已经绑定好的函数和参数会被执行。 举个例子: 123456789101112#include <iostream>#include <functional>void add(int a, int b) { std::cout << "Sum: " << a + b << std::endl;}int main() { // 使用 bind 绑定 add 函数和参数 auto bound_func = std::bind(add, 3, 4); bound_func(); // 执行 add(3, 4)} 在这个例子中,std::bind 将 add 函数与参数 3 和 4 绑定,返回的 bound_func 是一个可调用对象,调用时就相当于执行了 add(3,...
《C++ Concurrency in Action》第二章
这本书主要讲的是c++多线程编程相关的内容,第二章主要讲的是std:thread的使用注意事项 线程的启动在使用std:thread时,我们要注意的一点是c++中的语法解析,原文是(c++’s most vexing parse). 函数对象(Functors)即任何重载了 operator() 的类的实例。Lambda 表达式是匿名函数对象的语法糖 如果将函数对象作为thread的构造函数参数而不是普通的函数对象,就注意不要使用临时变量 123456789struct fun { void operator()() { std::cout << "MyFunctor is running in a thread!" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "MyFunctor finished." <<...
c中的协程(三)
在 C++20 中,协程由多个部分组成,其中 等待体、协程体 和 promise_type 是关键组成部分。它们各自负责协程的不同方面,密切配合,共同完成协程的生命周期管理、执行与返回值的处理。 关系概述: 协程体(Coroutine Body)是我们定义的协程函数,即用户定义的异步操作逻辑,通常包含 co_await、co_yield 和 co_return 等操作。 等待体(Awaitable)是协程体中通过 co_await 关键字进行挂起的对象。它定义了协程如何挂起并等待某些异步操作的完成。 promise_type 是协程的内部管理对象,负责协程的生命周期,包括挂起、恢复、返回值以及异常的处理。每个协程都会有一个与之关联的 promise_type,它控制协程体的行为和返回值的处理。 它们的具体关系: 协程体 会依赖 promise_type 来控制协程的执行和返回值。 promise_type 负责管理协程的状态,包括决定何时挂起和恢复协程,以及处理协程的返回值。 等待体 是协程体中通过 co_await...
c中的协程(二)
栈协程(Stackful Coroutine)和无栈协程(Stackless Coroutine)的底层原理和实现方式有很大的区别,特别是在如何管理协程的执行状态、内存和栈的分配上。它们分别采用不同的策略来实现协程的暂停与恢复,以下是它们的具体实现方式、区别和底层原理的详细解析。 1. 栈协程(Stackful Coroutine)栈协程的基本原理是为每个协程分配一个独立的栈空间。栈空间用于保存协程的局部变量、函数调用的状态(比如返回地址、参数、局部数据)以及执行的上下文。当协程暂停时,整个栈内容(包括程序计数器、寄存器等)都会被保存;当协程恢复时,这些状态会被恢复,栈继续执行。 栈协程的实现方式:栈协程的底层实现一般需要依赖操作系统提供的线程或者使用一些低级的上下文切换机制,常见的有: 使用线程:栈协程的实现有时会通过操作系统的线程来模拟。每个协程有独立的栈和线程上下文,操作系统调度器负责协程的切换。 例子: boost::context 或 libco 等库,使用 setjmp 和 longjmp 来保存和恢复栈状态,或者使用线程来模拟协程。 **使用 setjmp...
Rangers库
好的,我们来详细聊聊 C++20 引入的 Ranges 库。 Ranges 库是 C++20 中一个非常重要的特性,它彻底改变了我们在 C++ 中处理序列(集合、容器)的方式。它的核心思想是提供一种组合式 (composable)、声明式 (declarative)、惰性求值 (lazy evaluation) 的方式来操作数据序列,从而使得代码更简洁、更易读、更安全、更高效。 1. 为什么需要 Ranges 库?在 C++20 之前,我们主要使用标准库算法(如 std::for_each, std::transform, std::sort 等)配合迭代器对来操作序列: 1234567891011121314151617181920212223242526272829303132#include <vector>#include <algorithm> // for std::transform, std::for_each#include <iostream>#include <numeric> // for...
concepts
在 C++20 中,”约束” (Constraints) 主要指的是 **概念 (Concepts)**。它是 C++ 模板编程中的一个革命性特性,旨在解决传统模板编程中的一些核心痛点。 简单来说,概念 (Concept) 允许你指定模板参数必须满足的条件或要求。 1. 为什么需要概念 (Concepts)?在 C++20 之前,我们编写泛型代码(模板)时,编译器通常只在实例化模板时才检查模板参数是否“合适”。如果参数不合适,就会导致非常冗长、难以理解的编译错误信息,这被称为 SFINAE (Substitution Failure Is Not An Error) 的副作用。 考虑一个简单的例子: 1234567891011121314// C++11/14/17template <typename T>void print_sum(T a, T b) { std::cout << a + b << std::endl;}int main() { print_sum(1, 2); // OK ...
span
std::span 是 C++20 引入的一个非常实用的特性,它提供了一个非拥有 (non-owning) 的、**连续内存区域的视图 (view)**。你可以把它理解为 std::string_view 的泛化版本,std::string_view 是 char 序列的非拥有视图,而 std::span 是任意类型 T 的序列的非拥有视图。 std::span 的核心思想和解决的问题在 C++20 之前,我们经常需要处理连续内存区域,例如: C 风格数组 (int arr[10];) std::vector std::array 其他自定义的连续内存容器 当我们需要将这些数据传递给函数时,通常有几种方式: 原始指针和长度: void func(int* data, size_t size); 这种方式容易出错,容易忘记传递长度,或者长度与实际数据不匹配,导致越界访问。 const std::vector<T>&: 如果函数只读取数据,这种方式比较安全。但如果函数只需要一部分数据,或者数据来源不是...
IPC通信
一、引言上班要用,临时抱佛脚学一下,引用进程间通信 IPC 完全指南:各种机制的原理与实战-腾讯云开发者社区-腾讯云 在现代计算系统中,多进程环境已经成为标准配置。随着计算需求的增长和应用复杂性的提升,单一进程往往无法独立完成所有任务。为了提高系统的灵活性、性能和可靠性,多个进程之间的协作成为了必然的选择。这就引出了一个关键问题:如何高效、安全地实现进程间的数据交换与通信?这就是进程间通信(Inter-Process...
mutex底层原理
std::mutex(互斥锁)是 C++ 中用于实现互斥访问共享资源的关键工具。它的底层原理涉及到操作系统、CPU硬件指令以及内存模型等多个层面。理解这些底层机制对于编写高效、正确的并发程序至关重要。 1. 为什么需要 Mutex?在多线程环境中,当多个线程尝试同时访问和修改同一个共享资源(如变量、数据结构、文件等)时,如果没有适当的同步机制,就可能发生**竞态条件 (Race Condition)**,导致数据损坏或程序行为不可预测。 示例: 12345678int counter = 0;void increment() { for (int i = 0; i < 100000; ++i) { counter++; // 这不是一个原子操作 }}// 两个线程同时调用 increment(),counter 的最终值可能不是 200000 counter++ 表面上是一行代码,但在 CPU 层面可能被分解为以下步骤: 读取 counter 的当前值到寄存器。 寄存器中的值加...
c++中的协程(一)
在学习协程之前,我们再重新回顾一下进程,线程 进程 (Process): 操作系统分配资源(内存、文件句柄等)的基本单位。每个进程有独立的地址空间。 线程 (Thread): CPU 调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的地址空间和资源。线程比进程更轻量级。 1. 内核线程 (Kernel Thread) 定义: 内核线程是由操作系统内核直接创建、管理和调度的线程。也就是我们说的LWP(轻量级进程),在linux系统中,内核线程和用户态线程是1:1的。 实现: 操作系统内核维护所有内核线程的上下文信息(如寄存器状态、栈指针等)。当需要进行线程切换时,内核会执行上下文切换。 调度: 由操作系统的调度器负责调度。调度器根据优先级、时间片等策略决定哪个线程在哪个 CPU 上运行。 开销: 创建/销毁: 创建和销毁内核线程的开销相对较大,因为它涉及到系统调用和内核数据结构的操作。 上下文切换: 上下文切换的开销也相对较大,因为它需要保存和恢复大量的寄存器信息,并且可能涉及到 TLB (Translation Lookaside Buffer)...




