如何实现条件_variable?
标题问题的较长版本是:
在我的计算机上,
sizeof(std :: condition_variable)
是72个字节。 这些72个字节是用什么?
注意: std :: condition_variable
的大小取决于实现。
附录 notify_one
和成员对象。我将从等待
开始。 等待
带有谓词。
template <class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { // wait for signal and test predicate
while (!_Pred()) {
wait(_Lck);
}
}
上面的等待
调用no-prodicate 等待
。
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
on _MYCND()
。 _CND_WAIT
找到。
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_T
的指针。
using _Cnd_t = struct _Cnd_internal_imp_t*;
struct _cnd_internal_imp_t
是定义的。
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-&gt; _get_cv() - &gt; wait(cs);
。要理解这一行,我需要查看并发::详细信息:: stl_condition_variable_interface
的成员 wait
函数。这是一个
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-&gt; _get_cv()
是抽象类 stl_condition_variable_interface
的指针。在施工期间的某个时候, 将被调用以设置虚拟指针。 The virtual pointer for this object will point to the vtable for either stl_condition_variable_vista
given
就我而言,虚拟指针指向 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
,而的精华等待
是调用 SleepConditionVariablesrw
。描述了此功能
结束编辑2
附录a
std :: condition_variable
is
aligned_storage_t<_Cnd_internal_imp_size, _Cnd_internal_imp_alignment> _Cnd_storage;
std :: procention_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_ind_internal_imp_size
。实际上,这在此
static_assert(sizeof(_Cnd_internal_imp_t) <= _Cnd_internal_imp_size, "incorrect _Cnd_internal_imp_size");
这意味着72个字节中的一些可能是“未使用的”。
结束编辑1
问题:
-
std :: procention_variable
保留72个字节,以condition> procention_variable
(请参阅编辑2)。这些72个字节是用什么? -
std :: condition_variable
如何使用更少的字节逃脱?似乎在某些计算机上std :: procenty_variable
s只有8个字节大。看:_inline_var constexpr size_t _cnd_internal_imp_size = 8;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
条件变量的另一个实现是由并发运行时(Concrt)支持的。在Visual Studio 2012中,这是唯一的实现,但事实证明不是很好。
从VS 2015开始,由实际的
条件_variable
提供更好的实现。有一个多态性来为不同的Windows版本创建不同的实现,因为condition_variable
可以使用Windows Vista,并且A 完整srwlock
从Windows 7. The polymorphism uses placement new rather than unions to hide the implementation details and to make the implementation conformant by因此,有一个用于多个实现的地方,其中的具体是最大的。
否则,
sizeof(condition_variable)== sizeof(void*)
以及sizeof(srwlock)== sizeof(void*)
,尽管它们不是内部指针。如果code> condition_variable
/srwlock
使用实现,则浪费了其余大小。从Visual Studio 2019开始,Windows XP不再得到VS工具集的支持(由VS 2019支持安装VS 2017 Toolset的VS 2019支持)。因此,” norefloll noreferrer“> noreflow noreferrer”>我的pr 。 后续pr 删除了混合结构包装器。
从Visual Studio 2022开始,Windows Vista不再得到VS工具集的支持/a>删除
srwlock
多态性正在飞行。仍然是由于VS 2015,VS 2017,VS 2019和VS 2022之间的ABI兼容性,因此不可能减少
condition> condition_variable
的大小。在
mutex
构造函数中摆脱新的位置,并解决了具有mutex
sonstructor non-constexpr
的符合性问题(我的尝试失败)。因此,vs 2019和vs 2022仍然必须为具体实施预留空间,这不再使用。
随着ABI的下一个ABI破坏版本的发布,很有可能实施
条件_variable
将更改。_CRT_WINDOWS
实现不需要支持Windows XP,因此没有Concrt后备。仍然出于维护原因,它仍然与通常的配置共享实现。There was another implementation of condition variable that was backed by Concurrency Runtime (ConcRT). In Visual Studio 2012 it was the only implementation, but it turned out to be not very good.
Starting from VS 2015, there is better implementation backed by the actual
CONDITION_VARIABLE
. There is a polymorphism to create different implementations for different Windows versions, asCONDITION_VARIABLE
is available starting Windows Vista, and a completeSRWLOCK
is available starting in Windows 7. The polymorphism uses placement new rather than unions to hide the implementation details and to make the implementation conformant by making it a standard-layout class.So, there is a place for multiple implementations, out of which the ConcRT is the largest.
Otherwise,
sizeof(CONDITION_VARIABLE) == sizeof(void*)
, as well assizeof(SRWLOCK) == sizeof(void*)
, though they aren't pointers internally. The rest of the size is wasted, ifCONDITION_VARIABLE
/SRWLOCK
implementation is used.Starting from Visual Studio 2019, Windows XP is no longer supported by the VS toolset (it is supported by VS 2019 by the ability to install VS 2017 toolset). So ConcRT dependency and the ability to create pre-Vista
condition_variable
was removed by my PR. A follow-up PR removed ConcRT structure wrappers.Starting from Visual Studio 2022, Windows Vista is no longer supported by the VS toolset either, my other PR to remove the
SRWLOCK
polymorphism is in flight.Still due to the ABI compatibility between VS 2015, VS 2017, VS 2019, and VS 2022, it is not possible to reduce the size of
condition_variable
.Getting rid of placement new in
mutex
constructor and fixing the conformance issue with havingmutex
constructor non-constexpr
is also hard (my attempt has failed).So, VS 2019 and VS 2022 still have to reserve space for the ConcRT implementation, which is no longer used.
With the next ABI breaking release of Visual Studio it is highly likely that the implementation of
condition_variable
will change._CRT_WINDOWS
implementation never needed to support Windows XP, so does not have ConcRT fallback. Still it shares the implementation with the usual configuration, apparently for maintenance reasons.这是一个不完整的答案,但确实提供了更多信息。
std :: condition_variable
调用一个函数的构造函数,该函数在_cnd_storage
/code 定义时存储的数据有2个指针,或一个指针和一个指针大小的整数;第一个可能是虚拟函数指针(指向
stl_condition_variable_interface
),另一个是状态。根据您使用的操作系统和库提供的内容,或多或少需要在条件变量实现中进行机械。
该实现可能是在您似乎无法访问的源代码中。
https://github.com/ojdkbuild/tools_toolchain_vs2017bt_1416/blob/blob/master/master/vc/tools/tools/mmsvc/14.16.27023/crt/crt/src/src/stl/stl/cond.c.到
并发::详细信息:: create_stl_condition_variable(cond-&gt; _get_cv())
。在这里:: _ procenty_variable 。但是,它似乎并不是那里创建的东西(它没有虚拟基础)。它有两个成员:
可能与实际存储的成员相似(因为这是对类似事物的先前实现)。对于
std
procention_variable
,关键部分可能是冗余的,因为它具有外部静音。除
_M_PWAITCHAIN
中,我不能说。所有这些都不完整。我确实知道,现代状况变量知道何时握住锁定时会发出信号,并在释放互惠符时与线程醒来的互动。即,操作系统调度物质内部的低水平。
This is an incomplete answer, but it does provide more information.
The constructor of
std::condition_variable
calls a function that creates the implementation of the condition variable within_Cnd_storage
when
_CRT_WINDOWS
is defined, it appears that the data stored there is 2 pointers, or one pointer and one integer the size of a pointer; the first of which is probably a virtual function pointer (pointing at thestl_condition_variable_interface
), and the other one is the state.Depending on what the OS and libraries you are using provide, more or less machinery needs to be in the condition variable implementation.
That implementation may be in source code you do not appear to have access to.
https://github.com/ojdkbuild/tools_toolchain_vs2017bt_1416/blob/master/VC/Tools/MSVC/14.16.27023/crt/src/stl/cond.c appears to be
_Cnd_init_in_situ
, which simply forwards toConcurrency::details::create_stl_condition_variable(cond->_get_cv())
.Here is a VS2013
Concurrency::detalis::_Condition_variable
. It, however, does not appear to be what is created there (it has no virtual base). It has two members:which may be similar to what is actually stored there (as it was a previous implementation for something similar). The critical section is probably redundant for a
std
condition_variable
, as it has an external mutex to work with.What is in the
_M_pWaitChain
I cannot say, other than from its name.All of this isn't complete. I do know that modern condition variables know when they are signaled if they are holding the lock, and interact with which thread wakes up when the mutex is released; ie, low level internal to OS scheduling stuff.