传统上,C++ 库由一个头文件 + 编译成二进制文件(.a
, .so
, .dylib
, .dll
, ...)的实现组成。头文件#include
在源代码中是d,二进制部分链接到最终的可执行文件。
C++20 的模块会改变这种布局吗?如果是这样,操作系统是否必须升级它们分发核心库的方式,例如 Linux 中的标准库或 Windows 中的其他核心 dll?
原子新手在这里.我的代码目前看起来像这样(简化):
std::atomic<Object*> object;
void thread_a()
{
object.load()->doSomething(); // (1)
}
void thread_b()
{
Object* oldObject = object.load();
Object* newObject = new Object();
// Update new object accordingly...
while (!object.compare_exchange_weak(oldObject, newObject));
delete oldObject;
}
Run Code Online (Sandbox Code Playgroud)
换句话说,我的想法是让thread_b
原子交换共享对象(双缓冲),同时thread_a
对它执行一些工作.我的问题:我可以安全地假设共享对象在对其进行thread_a
调用doSomething()
时会受到"保护" ,如(1)中所做的那样吗?
假设我的代码中包含以下全局变量:
std::atomic<uint32_t> x(...);
std::atomic<uint32_t> y(...);
std::atomic<uint32_t> z(...);
Run Code Online (Sandbox Code Playgroud)
我的任务是将x和y相乘,然后将结果存储在z中:
z = x * y
Run Code Online (Sandbox Code Playgroud)
我知道在每个对象上调用store()和load()的天真方法是完全错误的:
z.store(x.load() * y.load()); // wrong
Run Code Online (Sandbox Code Playgroud)
这样,我执行了三个单独的原子指令:另一个线程可能会滑过并同时更改其中一个值。
我可以选择比较交换(CAS)循环,但只能保证将旧值z
与新值(x*y
)交换时才具有原子性:我仍然不确定如何一次执行整个操作,原子步。
我也知道,包装x
,y
以及z
一个结构内,并使其原子是不可行这里,因为结构不适合一个64位寄存器内。编译器会在后台使用锁(如果我错了,请更正我)。
这个问题只能用互斥锁解决吗?
我有一个依赖于外部库(例如 SDL)的程序。我希望 CMake 为我处理这种依赖关系,所以我正在研究FetchContent
. 据我了解,该模块只是下载源代码,以便在配置时提供有关外部库的信息。例如:
include(FetchContent)
FetchContent_Declare(sdl
GIT_REPOSITORY <...>
)
FetchContent_GetProperties(sdl)
# sdl_POPULATED, sdl_SOURCE_DIR and sdl_BINARY_DIR are ready now
if(NOT sdl_POPULATED)
FetchContent_Populate(sdl)
endif()
Run Code Online (Sandbox Code Playgroud)
然而,在某些时候,我想构建该源代码并将其链接到我的主要可执行文件。如何以“现代 CMake 方式”做到这一点?
我想编写一个一次只能由一个线程访问的函数。我不需要忙碌的等待,如果另一个线程已经在运行它,那么残酷的“拒绝”就足够了。这是我到目前为止想出的:
std::atomic<bool> busy (false);
bool func()
{
if (m_busy.exchange(true) == true)
return false;
// ... do stuff ...
m_busy.exchange(false);
return true;
}
Run Code Online (Sandbox Code Playgroud)
std::memory_order_acq_rel
?据我了解,宽松的排序 ( std::memory_order_relaxed
) 不足以防止重新排序。我很难找到如何使用VST 3.x SDK设置最小插件主机的基本示例.官方文档绝对是残忍和短暂的,我无法到达任何地方.我想要:
那将是一个很好的开始:)
假设我有一个包含std::atomic_flag
私有成员的类,通过getter公开.类似下面的内容(伪代码):
class Thing
{
private:
std::atomic_flag ready = ATOMIC_FLAG_INIT;
public:
isReady()
{
return ready.test_and_set();
}
}
Run Code Online (Sandbox Code Playgroud)
我天真的问题是:通过一个方法查询标志,将其转换为非原子操作,是一个非原子的函数调用(或者是?)?我应该将我的ready
旗帜作为公共成员并直接查询吗?
我读这篇文章由Herb萨特关于通过智能函数指针.他没有提到std::weak_ptr
,老实说,我找不到一个好的方案,传递这样的智能指针是有用的.
该功能是否拥有所有权?通过std::shared_ptr
.该函数是否只需要对底层对象进行操作?传递原始指针或引用.
所以传递std::weak_ptr
给100%无用的功能?
CAS属于读-修改-写(RMW)系列,这是一组算法,可让您自动执行复杂的事务。
具体来说,维基百科说
CAS用于实现同步原语,例如信号量和互斥量,以及更复杂的无锁和无等待算法。相对于原子读取,写入或获取和添加,CAS可以实现更多的这些算法,并且假设有相当大的内存,它可以实现所有这些。
https://zh.wikipedia.org/wiki/Compare-and-swap#概述
因此,似乎CAS算法就是其同类产品的“一刀切”。为什么?其他RMW算法缺少什么?如果CAS是最好的工具,那么其他算法还有什么用呢?
language-agnostic algorithm concurrency multithreading atomic
考虑以下取自维基百科的示例,稍作修改,其中程序的步骤对应于各个处理器指令:
x = 0;
f = 0;
Thread #1:
while (f == 0);
print x;
Thread #2:
x = 42;
f = 1;
Run Code Online (Sandbox Code Playgroud)
我知道,print
由于乱序执行,当线程在两个不同的物理内核/处理器上运行时,该语句可能会打印不同的值(42 或 0)。
但是我不明白为什么这在单核机器上不是问题,这两个线程运行在同一个核心上(通过抢占)。根据维基百科:
当程序在单 CPU 机器上运行时,硬件执行必要的簿记以确保程序执行时好像所有内存操作都按照程序员指定的顺序(程序顺序)执行,因此不需要内存屏障。
据我所知,单核 CPU 也会对内存访问重新排序(如果它们的内存模型很弱),那么是什么确保程序顺序被保留呢?
multithreading synchronization cpu-architecture low-level memory-barriers