C++20 latch
7168 ワード
vs2019 C++20 latch 01 latch 02 latchの実装 01 latch
スレッドは、カウンタがゼロに減少するまでlatchでブロックされる可能性があります.カウンタを追加またはリセットすることはできません.これにより、latchは単一使用のバリアになります.
同時にlatchのメンバー関数を呼び出し、構造関数を除いてデータ競合を導入しません.
std::barrierとは異なり、参加スレッドはstd::latchを1回以上減らすことができます.1
方法
さぎょう
latch
割り当て不可
count_down
カウンタをブロックせずに削減
try_wait
内部カウンタがゼロに等しいかどうかをテストします
wait
カウンタがゼロに達するまでブロック
arrive_and_wait
カウンタを減らしてゼロに達するまでブロックします
max
[静的]サポートされているカウンタの最大値を実現
latchのリファレンスヘッダファイルstd::latch 2
02 latchの実装
githubの上にlatchの実装(linux,macos,windowsの実装)が見つかりました.https://github.com/luncliff/latch
ここにwindowsの上の実装が貼られています.開発がまた必要なら、このオープンソースを先に使ったほうがいいです.このlatchはwindows上の実装に重点を置いて
std::latch ↩︎
標準ヘッダファイル
ラッチ:1回使用するスレッドバリア.latchはptrdiff_tタイプのダウンカウンタで、スレッドを同期するために使用できます.作成時にカウンタの値を初期化します.スレッドは、カウンタがゼロに減少するまでlatchでブロックされる可能性があります.カウンタを追加またはリセットすることはできません.これにより、latchは単一使用のバリアになります.
同時にlatchのメンバー関数を呼び出し、構造関数を除いてデータ競合を導入しません.
std::barrierとは異なり、参加スレッドはstd::latchを1回以上減らすことができます.1
方法
さぎょう
latch
割り当て不可
count_down
カウンタをブロックせずに削減
try_wait
内部カウンタがゼロに等しいかどうかをテストします
wait
カウンタがゼロに達するまでブロック
arrive_and_wait
カウンタを減らしてゼロに達するまでブロックします
max
[静的]サポートされているカウンタの最大値を実現
latchのリファレンスヘッダファイルstd::latch 2
namespace std {
class latch {
public:
static constexpr ptrdiff_t max() noexcept;
constexpr explicit latch(ptrdiff_t expected);
~latch();
latch(const latch&) = delete;
latch& operator=(const latch&) = delete;
void count_down(ptrdiff_t update = 1);
bool try_wait() const noexcept;
void wait() const;
void arrive_and_wait(ptrdiff_t update = 1);
private:
ptrdiff_t counter; //
};
}
02 latchの実装
githubの上にlatchの実装(linux,macos,windowsの実装)が見つかりました.https://github.com/luncliff/latch
ここにwindowsの上の実装が貼られています.開発がまた必要なら、このオープンソースを先に使ったほうがいいです.このlatchはwindows上の実装に重点を置いて
WakeByAddressAll
,WaitOnAddress
,InterlockedAdd
,InterlockedAdd64
の4つのapiを使用した.latch.h
#pragma once
#include
namespace std {
/**
* @defgroup thread.coord
* Concepts related to thread coordination, and defines the coordination types `latch` and `barrier`.
* These types facilitate concurrent computation performed by a number of threads.
*/
/**
* @brief Allows any number of threads to block until an expected number of threads arrive at the latch
* @ingroup thread.coord
*
* A `latch` is a thread coordination mechanism that allows any number of threads
* to block until an expected number of threads arrive at the `latch`
* (via the `count_down` function).
*
* The expected count is set when the `latch` is created.
* An individual `latch` is a single-use object;
* once the expected count has been reached, the `latch` cannot be reused.
*
* @see N4835, 1571~1572p
*/
class latch {
public:
/**
* @brief upper limit on the value of `expected` for constructor of `latch`
* @return ptrdiff_t The maximum value of counter that the implementation supports
* @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1865r1.html
* @see /proc/sys/kernel/threads-max
*/
static constexpr ptrdiff_t max() noexcept {
return 32;
}
public:
/**
* @brief Initialize `counter` with `expected`
* @param expected
* @pre `expected >= 0` is true
*/
constexpr explicit latch(ptrdiff_t expected) noexcept : counter{expected} {
}
/**
* Concurrent invocations of the member functions of `latch` other than its destructor,
* do not introduce data races
*/
~latch() = default;
latch(const latch&) = delete;
latch& operator=(const latch&) = delete;
/**
* **Synchronization**:
* Strongly happens before the returns from all calls that are unblocked.
*
* **Error Conditions**:
* Any of the error conditions allowed for mutex types (32.5.3.2)
*
* @param update
* @pre `update >= 0` is true, and `update <= counter` is true
* @post Atomically decreses `counter` by `update`.
* If `counter` is equal to zero, unblocks all threads blocked on `*this`
* @throw system_error
*/
void count_down(ptrdiff_t update = 1) noexcept(false);
/**
* @return true `counter` equals zero
* @return false Very low probability of failure from system call
*/
bool try_wait() const noexcept;
/**
* If `counter` equals zero, returns immediately.
* Otherwise, blocks on `*this` until a call to `count_down` that decrements `counter` to zero
*
* @throw system_error
*/
void wait() const noexcept(false);
/**
* @param update input for `count_down`
* @see count_down
* @see wait
*/
void arrive_and_wait(ptrdiff_t update = 1) noexcept(false);
private:
/**
* @brief A latch maintains an internal counter
*
* A latch maintains an internal counter that is initialized when the latch is created
* Threads can block on the latch object, waiting for counter to be decremented to zero.
*/
ptrdiff_t counter;
};
} // namespace std
latch_windows.cpp
#include "latch.h"
#include
#include
#include
// clang-format off
#include
#include
// clang-format on
namespace std {
static_assert(is_copy_assignable_v == false);
static_assert(is_copy_constructible_v == false);
void latch::arrive_and_wait(ptrdiff_t update) noexcept(false) {
this->count_down(update);
this->wait();
}
void latch::count_down(ptrdiff_t update) noexcept(false) {
static_assert(is_same_v || is_same_v);
if (counter < update)
throw system_error{EINVAL, system_category(),
"update is greater than counter"};
// if not lock-free, rely on InterLocked operation
if constexpr (atomic::is_always_lock_free) {
counter -= update;
} else if constexpr (is_same_v) {
InterlockedAdd(reinterpret_cast(&counter),
static_cast(-update));
} else if constexpr (is_same_v) {
InterlockedAdd64(reinterpret_cast(&counter),
static_cast(-update));
}
// counter reached zero
if (counter == 0)
WakeByAddressAll(&counter);
}
bool latch::try_wait() const noexcept {
// if counter equals zero, returns immediately
if (counter == 0)
return true;
// blocks on `*this` until a call to count_down that decrements counter to zero
ptrdiff_t captured = counter;
if (WaitOnAddress(const_cast(&counter), &captured,
sizeof(ptrdiff_t), INFINITE))
return counter == 0;
// caller can check `GetLastError` for this case
return false;
}
void latch::wait() const noexcept(false) {
while (try_wait() == false) {
// case: error from WaitOnAddress
if (const auto ec = GetLastError())
throw system_error{static_cast(ec), system_category(),
"WaitOnAddress"};
// case: counter != 0. retry
// ...
}
}
} // namespace std
std::latch ↩︎
標準ヘッダファイル
↩︎