- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
标题问题的较长版本是:
On my machine,
sizeof(std::condition_variable)
is 72 bytes.What are these 72 bytes used for?
注意:std::condition_variable
的大小取决于实现。 附录 A 中给出了一些示例尺寸。
了解如何std::condition_variable
作品,我很满意理解wait
, notify_one
, 和成员对象。我将从 wait
开始. wait
下面给出了一个谓词。
template <class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { // wait for signal and test predicate
while (!_Pred()) {
wait(_Lck);
}
}
以上wait
调用无谓词 wait
.
void wait(unique_lock<mutex>& _Lck) { // wait for signal
// Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow
_Cnd_wait(_Mycnd(), _Lck.mutex()->_Mymtx());
}
此等待调用 _Cnd_wait
在 _Mycnd()
. _Cnd_wait
找到here .
int _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled
const auto cs = static_cast<Concurrency::details::stl_critical_section_interface*>(_Mtx_getconcrtcs(mtx));
_Mtx_clear_owner(mtx);
cond->_get_cv()->wait(cs);
_Mtx_reset_owner(mtx);
return _Thrd_success; // TRANSITION, ABI: Always returns _Thrd_success
}
_Cnd_t
是指向 _Cnd_internal_imp_t
的指针.
using _Cnd_t = struct _Cnd_internal_imp_t*;
结构_Cnd_internal_imp_t
定义 here .
struct _Cnd_internal_imp_t { // condition variable implementation for ConcRT
std::aligned_storage_t<Concurrency::details::stl_condition_variable_max_size,
Concurrency::details::stl_condition_variable_max_alignment>
cv;
[[nodiscard]] Concurrency::details::stl_condition_variable_interface* _get_cv() noexcept {
// get pointer to implementation
return reinterpret_cast<Concurrency::details::stl_condition_variable_interface*>(&cv);
}
};
我现在正在查看 cond->_get_cv()->wait(cs);
行.要理解这一行,我需要查看 Concurrency::details::stl_condition_variable_interface
的成员(member)wait
功能。这是 virtual function .
class __declspec(novtable) stl_condition_variable_interface {
public:
virtual void wait(stl_critical_section_interface*) = 0;
virtual bool wait_for(stl_critical_section_interface*, unsigned int) = 0;
virtual void notify_one() = 0;
virtual void notify_all() = 0;
virtual void destroy() = 0;
};
编辑2
cond->_get_cv()
是指向抽象类的指针 stl_condition_variable_interface
.在施工期间的某个时刻, create_stl_condition_variable
将被调用以设置虚拟指针。此对象的虚拟指针将指向 stl_condition_variable_vista
的 vtable。给出here或 stl_condition_variable_win7
给出here . this 的最佳答案堆栈溢出问题解释了一些细节。
在我的例子中,虚拟指针指向 stl_condition_variable_win7
的表.
class stl_condition_variable_win7 final : public stl_condition_variable_interface {
public:
stl_condition_variable_win7() {
InitializeConditionVariable(&m_condition_variable);
}
~stl_condition_variable_win7() = delete;
stl_condition_variable_win7(const stl_condition_variable_win7&) = delete;
stl_condition_variable_win7& operator=(const stl_condition_variable_win7&) = delete;
void destroy() override {}
void wait(stl_critical_section_interface* lock) override {
if (!stl_condition_variable_win7::wait_for(lock, INFINITE)) {
std::terminate();
}
}
bool wait_for(stl_critical_section_interface* lock, unsigned int timeout) override {
return SleepConditionVariableSRW(&m_condition_variable,
static_cast<stl_critical_section_win7*>(lock)->native_handle(), timeout, 0)
!= 0;
}
void notify_one() override {
WakeConditionVariable(&m_condition_variable);
}
void notify_all() override {
WakeAllConditionVariable(&m_condition_variable);
}
private:
CONDITION_VARIABLE m_condition_variable;
};
所以我保留了 72 或 8 个字节来存储一个 CONDITION_VARIABLE
和wait
的本质就是打电话SleepConditionVariableSRW
.此功能描述 here .
结束编辑 2
附录 A
std::condition_variable
的唯一成员对象是
aligned_storage_t<_Cnd_internal_imp_size, _Cnd_internal_imp_alignment> _Cnd_storage;
std::condition_variable
包含以下允许 _Cnd_storage
的成员函数被解释为 _Cnd_t
.
_Cnd_t _Mycnd() noexcept { // get pointer to _Cnd_internal_imp_t inside _Cnd_storage
return reinterpret_cast<_Cnd_t>(&_Cnd_storage);
}
sizeof(std::condition_variable)
由 sizeof(_Cnd_storage)
给出,在 xthreads.h
中定义.
// Size and alignment for _Mtx_internal_imp_t and _Cnd_internal_imp_t
#ifdef _CRT_WINDOWS
#ifdef _WIN64
_INLINE_VAR constexpr size_t _Mtx_internal_imp_size = 32;
_INLINE_VAR constexpr size_t _Mtx_internal_imp_alignment = 8;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_size = 16;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_alignment = 8;
#else // _WIN64
_INLINE_VAR constexpr size_t _Mtx_internal_imp_size = 20;
_INLINE_VAR constexpr size_t _Mtx_internal_imp_alignment = 4;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_size = 8;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_alignment = 4;
#endif // _WIN64
#else // _CRT_WINDOWS
#ifdef _WIN64
_INLINE_VAR constexpr size_t _Mtx_internal_imp_size = 80;
_INLINE_VAR constexpr size_t _Mtx_internal_imp_alignment = 8;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_size = 72;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_alignment = 8;
#else // _WIN64
_INLINE_VAR constexpr size_t _Mtx_internal_imp_size = 48;
_INLINE_VAR constexpr size_t _Mtx_internal_imp_alignment = 4;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_size = 40;
_INLINE_VAR constexpr size_t _Cnd_internal_imp_alignment = 4;
#endif // _WIN64
#endif // _CRT_WINDOWS
编辑 1/附录 B
我在发布问题后考虑了这个问题,但我不确定如何让它与其他问题一起流动。 std::condition_variable
的唯一成员是
aligned_storage_t<_Cnd_internal_imp_size, _Cnd_internal_imp_alignment> _Cnd_storage;
被解释为 _Cnd_internal_imp_t
. _Cnd_internal_imp_t
的唯一成员是
std::aligned_storage_t<Concurrency::details::stl_condition_variable_max_size, Concurrency::details::stl_condition_variable_max_alignment> cv;
有可能stl_condition_variable_max_size != _Cnd_internal_imp_size
.事实上,这暗示在这个 line
static_assert(sizeof(_Cnd_internal_imp_t) <= _Cnd_internal_imp_size, "incorrect _Cnd_internal_imp_size");
这意味着 72 个字节中的一些可能是“未使用的”。
结束编辑 1
问题:
std::condition_variable
为 CONDITION_VARIABLE
保留 72 个字节(见编辑 2)。这 72 个字节有什么用?std::condition_variable
用更少的字节逃脱?在某些机器上看起来好像std::condition_variable
s 只有 8 个字节大。看: _INLINE_VAR constexpr size_t _Cnd_internal_imp_size = 8;
最佳答案
std::condition_variable
reserves 72 bytes for a CONDITION_VARIABLE (see Edit 2). What are these 72 bytes used for?
还有另一种由并发运行时 (ConcRT) 支持的条件变量实现。在 Visual Studio 2012 中,它是唯一的实现,但结果并不是很好。
从 VS 2015 开始,实际 CONDITION_VARIABLE
支持更好的实现。有一种多态性可以为不同的 Windows 版本创建不同的实现,因为 CONDITION_VARIABLE
从 Windows Vista 开始可用,complete SRWLOCK
从 Windows Vista 开始可用Windows 7。多态性使用 placement new 而不是 union 来隐藏实现细节并使实现符合 making it a standard-layout class 。
因此,有多个实现的地方,其中 ConcRT 是最大的。
否则,sizeof(CONDITION_VARIABLE) == sizeof(void*)
,以及 sizeof(SRWLOCK) == sizeof(void*)
,尽管它们不是t 内部指针。如果使用 CONDITION_VARIABLE
/SRWLOCK
实现,则剩余的大小将被浪费。
从 Visual Studio 2019 开始,VS 工具集不再支持 Windows XP(VS 2019 支持安装 VS 2017 工具集)。因此,my PR 删除了 ConcRT 依赖性和创建 pre-Vista condition_variable
的能力。 A follow-up PR 删除了 ConcRT 结构包装器。
从 Visual Studio 2022 开始,VS 工具集也不再支持 Windows Vista,删除 SRWLOCK
多态性的 my other PR 正在运行中。
仍然由于 VS 2015、VS 2017、VS 2019 和 VS 2022 之间的 ABI 兼容性,无法减小 condition_variable
的大小。
在 mutex
构造函数中摆脱 placement new 并修复 mutex
构造函数非 constexpr
的一致性问题也很困难 (my attempt has failed) .
所以VS 2019和VS 2022还是要为ConcRT实现预留空间,不再使用。
随着 Visual Studio 的下一个 ABI 中断版本,condition_variable
的实现很可能会发生变化。
How could a std::condition_variable get away with fewer bytes?
_CRT_WINDOWS
实现从来不需要支持 Windows XP,因此没有 ConcRT 回退。它仍然与通常的配置共享实现,显然是出于维护原因。
关于c++ - CONDITION_VARIABLE 是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72157532/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!