std::string 拼接操作的性能分析
C++ 标准库中提供的 std::string
类型有一些坑, 不小心使用的话很可能对程序性能造成影响. 例如字符串拼接这一常见简单的操作, 在 C++ 中大约有 4 种方式实现:
+
操作符+=
操作符append
成员stringstream
的<<
操作符
C++ 标准库中提供的 std::string
类型有一些坑, 不小心使用的话很可能对程序性能造成影响. 例如字符串拼接这一常见简单的操作, 在 C++ 中大约有 4 种方式实现:
+
操作符+=
操作符append
成员stringstream
的 <<
操作符一个简单的 std::function
实现, 能够完成基本功能, 即可以代理:
bind
表达式lambda
表达式以及普通 functor
functor
存储部分使用继承体系擦除 functor
类型, 保留返回值以及参数列表类型. 核心的调用部分则是直接使用 std::invoke
实现, 同时也没有做 functor
大小的区分, 统一存在堆上.
最近遇到这么一个问题: 给定一个点 $P$ 和三角形的三个点 $A, B, C$, 如何判断点 $P$ 是否在 $\triangle_{ABC}$ 内部?
「期值」是标准库为异步任务中返回值以及异常的传递提供的基础设施. 具体的做法是将这些值关联到共享的「future」对象上. 异步任务可以向这些期值对象中写入返回值或异常值, 异步任务的发起线程则可以通过这些期值对象等待, 读取, 检查其所需要的异步结果. 标准库中为上述功能提供的设施即 std::promise
和 std::future
.
Condition variable 和 Semaphore 是并发编程中用于同步控制和交互的原语. 多个并发线程可以使用 Condition variable 彼此交互, 一些线程可以通过 Condition variable 等待 (wait) 其他线程的通知 (notification). Condition variable 总是和 mutex 关联使用. Semaphore 相比 Condition variable 更加轻量, 它用来限制多个线程对共享资源的并发访问.
mutex
即 mutual exclusion, 表示一种互斥语义. 所谓互斥, 实际上是指所有权的唯一性, 即同一时刻一个互斥量只能由一个所有者持有. 在并发语境中, 互斥量这一原语的所有者一般是「线程」, 它的作用是用于阻止多个线程同时访问共享的资源, 从而避免 data race 并为多个线程的执行提供实现「同步」的机制.
Atomic 提供了开发高性能无锁 (lock free) 结构的工具和接口, 对于内置类型或自定义类型, 也可以通过 atomic<>
模板包装成支持原子操作的类型, 以实现并发安全.
C++ 17 提供了两个编译时常量, 用于表示 CPU Cache 的一些参数. 合理使用这两个编译时常量可以避免在多级 Cache 结构的计算机上并发程序频繁访问同一个对象不同成员时可能发生的 伪共享 (false sharing) 问题.
C++ 11 及之后的版本中提供了一系列并发编程的工具和对并发控制原语的抽象封装, 如 thread
, atomic
, mutex
, condition_varible
等. 本文介绍 thread
以及 jthread
的基本语义和功能, 它们在实际场景中的 best practice 和与之密切相关的编程模式不在本文讨论范围之内.
偶然在 vscode 的代码提示中看到了 thread_local
这个关键字, 心想 C++ 中什么时候提供了这种东西. 翻了下 cppreference 才知道早在 C++ 11 中就引入了这个修饰符, 用于声明线程生命周期. 趁此机会系统地看了下 C++ 变量的 4 种生命周期, 特此记录.