gpt4 book ai didi

c++ - CONDITION_VARIABLE 是如何实现的?

转载 作者:行者123 更新时间:2023-12-05 03:24:55 24 4
gpt4 key购买 nike

标题问题的较长版本是:

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。给出herestl_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_VARIABLEwait的本质就是打电话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

问题:

  1. std::condition_variableCONDITION_VARIABLE 保留 72 个字节(见编辑 2)。这 72 个字节有什么用?
  2. 怎么可能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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com