Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

sync::semaphore<N>:信号量

sync::semaphore<N> 表示一个“最多拥有 N 个许可(permit)”的计数信号量。

  • 当许可数大于 0 时,acquire()/try_acquire() 会消耗 1 个许可并成功返回。
  • 当许可数为 0 时,acquire() 会等待,直到有许可被释放。

常用别名:

  • sync::binary_semaphoresync::semaphore<1>
  • sync::unlimited_semaphore:许可上限非常大

头文件:asco/sync/semaphore.h


1. 构造与计数

sync::semaphore<3> sem{2};

语义:

  • 初始许可数为 min(N, count)
  • get_count() 返回当前许可数的一个瞬时值(可用于观测与调试;并发访问下不保证与后续操作之间的时序关系)。

2. 获取许可

2.1 try_acquire():非等待获取

bool ok = sem.try_acquire();

语义:

  • 若当前许可数大于 0:消耗 1 个许可并返回 true
  • 若当前许可数为 0:不等待,直接返回 false

2.2 acquire():等待获取

co_await sem.acquire();

语义:

  • 若当前许可数大于 0:消耗 1 个许可并返回。
  • 若当前许可数为 0:挂起等待,直到有其它执行流释放许可。
  • 支持任务取消。

acquire() 返回 future<void>,需要在 ASCO runtime 上下文中 co_await

2.3 blocking_acquire():同步等待获取

sem.blocking_acquire();

语义:

  • 同步地等待并获取 1 个许可。
  • 仅允许在“blocking 环境”中调用;否则会触发 panic
    • runtime 之外:允许(此时会阻塞当前线程)。
    • runtime 之内:仅当当前任务由 spawn_blocking(...) 启动(即 asco::this_task::is_blocking_env() == true)时允许。

3. 释放许可

3.1 release(n = 1)

std::size_t released = sem.release(5);

语义:

  • 向信号量增加最多 n 个许可。
  • 许可数不会超过上限 N
  • 返回值为“本次实际增加的许可数”。

当存在等待 acquire() 的执行流时,释放许可会让其中最多 released 个等待方继续执行;被唤醒的具体等待方不作保证。


4. 典型用法

4.1 binary_semaphore:一次只允许一个进入

#include <asco/sync/semaphore.h>
#include <asco/future.h>

using namespace asco;

future<void> f() {
    sync::binary_semaphore sem{1};
    co_await sem.acquire();
    // 临界区
    sem.release();
    co_return;
}

4.2 限流:最多并发 N 个任务

#include <asco/sync/semaphore.h>
#include <asco/core/runtime.h>
#include <asco/future.h>

using namespace asco;

future<void> limited(sync::semaphore<8> &sem) {
    co_await sem.acquire();
    // ... 执行受限工作
    sem.release();
    co_return;
}

5. 使用建议

  • 使用 try_acquire() 实现“尽力而为”的快速路径;失败时走其它分支。
  • 使用 acquire() 表达“必须获得许可才能继续”。
  • 不要在未获得许可时调用 release() 来“抵消”;这会破坏许可语义。