跳转至

6. Latch

使用下述功能需要包含头文件coke/latch.h

coke::Latch

coke::Latch提供了一种同步机制,允许协程等待直到内部计数器降到零,适用于需要在特定条件下协调多个协程的场景。

成员函数

  • 构造函数/析构函数

    创建一个可以精确计数n次的Latch,其中n >= 0。该类型不可移动、不可复制。

    explicit Latch(long n) noexcept;
    
    Latch(const Latch &) = delete;
    
    ~Latch();
    
  • 尝试等待

    检查内部计数器是否已达到零。若已经到达则返回true,否则返回false

    bool try_wait() const;
    
  • 等待计数器到达零

    等待直到内部计数器降到零。返回一个可等待的对象,调用者应立即使用co_await等待该对象完成。

    LatchAwaiter wait();
    
  • 等待计数器到达零或超时

    在指定的时间内等待计数器降到零。返回一个可等待的对象,调用者应立即使用co_await等待该对象完成,若等待超时,该对象返回coke::LATCH_TIMEOUT,若计数器到达零返回coke::LATCH_SUCCESS

    LatchAwaiter wait_for(NanoSec nsec);
    
  • 计数并等待

    将内部计数器减少nn应大于等于1,并等待计数器降到零。所有arrive_and_waitcount_down减少的计数总和,必须与构造该对象时期望的计数一致。返回一个可等待对象,调用者应立即使用co_await等待该对象完成。

    LatchAwaiter arrive_and_wait(long n = 1);
    
  • 减少计数

    将计数器减少n但不等待,其中n >= 1

    void count_down(long n = 1);
    

示例

#include <iostream>
#include <chrono>

#include "coke/latch.h"
#include "coke/sleep.h"
#include "coke/wait.h"

using namespace std::chrono_literals;

coke::Task<> worker(std::chrono::milliseconds ms, coke::Latch &lt) {
    co_await coke::sleep(ms);

    // 每完成一项就减少一次计数
    lt.count_down();
}

coke::Task<> wait_all() {
    coke::Latch lt(3);

    // 启动多个任务
    coke::detach(worker(100ms, lt));
    coke::detach(worker(200ms, lt));
    coke::detach(worker(300ms, lt));

    // 等待所有任务完成
    while (true) {
        int ret = co_await lt.wait_for(160ms);
        if (ret == coke::LATCH_TIMEOUT) {
            std::cout << "wait timeout" << std::endl;
            continue;
        }

        if (ret == coke::LATCH_SUCCESS) {
            std::cout << "wait success" << std::endl;
        }
        else {
            std::cout << "wait error " << ret << std::endl;
        }
        break;
    }
}

coke::Task<> wait_together(std::chrono::milliseconds ms, coke::Latch &lt) {
    std::cout << "start" << std::endl;
    co_await coke::sleep(ms);
    std::cout << "after sleep" << std::endl;

    // 等待所有相关工作都完成后,再一同开始后续任务
    co_await lt.arrive_and_wait();
    std::cout << "after all done" << std::endl;
}

int main() {
    coke::sync_wait(wait_all());

    coke::Latch lt(3);
    coke::sync_wait(
        wait_together(100ms, lt),
        wait_together(200ms, lt),
        wait_together(300ms, lt));
    return 0;
}

coke::SyncLatch

coke::SyncLatchcoke::Latch的同步版本。相比于std::latchcoke::SyncLatch可在协程中使用,当同步操作处于handler线程当中时,内部会再启动一个handler线程以避免该阻塞带来的影响。一般情况下不建议使用该类型。

成员函数

  • 构造函数

    创建一个可以精确计数n次的Latch,其中n >= 0。该类型不可移动、不可复制。

    explicit SyncLatch(long n);
    
    ~SyncLatch();
    
  • 减少计数

    SyncLatch的内部计数器减少n,其中n >= 1

    void count_down(long n = 1);
    
  • 等待计数器到达零

    同步等待直到SyncLatch的内部计数器降到零。

    void wait() const;