Skip to content

Commit

Permalink
add asynchronous semaphore implement & document
Browse files Browse the repository at this point in the history
  • Loading branch information
fawdlstty committed May 14, 2022
1 parent d45d4ca commit 38aa797
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 24 deletions.
39 changes: 38 additions & 1 deletion docs/en_us/6_Other.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ boost::asio::io_context &_ctx = fv::Tasks::GetContext ();

## Asynchronous mutex

Asynchronous mutex is a mutex suitable for asynchronous environments. In contrast to std::mutex, there are the following features:
Asynchronous mutex is a mutex suitable for asynchronous environments. In contrast to `std::mutex`, there are the following features:

- Supports asynchronous wait locking
- Locking and unlocking do not require the same thread
Expand Down Expand Up @@ -50,3 +50,40 @@ To know if it is locked:
```cpp
_mtx.IsLocked ();
```

## Asynchronous semaphore

An asynchronous semaphore is a semaphore suitable for asynchrony. In contrast to the library's `std::counting_semaphore`, there are the following features:

- Supports asynchronous wait for acquire

Create semaphore:

```cpp
AsyncSemaphore _sema { 1 }; // Parameter means the initial number of resources
```
Acquire resources:
```cpp
// try acquire resources
bool _acq = _sema.TryAcquire ();
// asynchronous acquire resources
co_await _mtx.Acquire ();
// asynchronous timeout acquire resources
bool _acq = co_await _mtx.Acquire (std::chrono::seconds (1));
```

Release resources:

```cpp
_mtx.Release ();
```

Get the count of available resources:

```cpp
_mtx.GetResCount ();
```
39 changes: 38 additions & 1 deletion docs/zh_hans/6_Other.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ boost::asio::io_context &_ctx = fv::Tasks::GetContext ();

## 异步锁

异步锁是一款适用于异步的锁。相对于标准库的 std::mutex 来说,有以下特性:
异步锁是一款适用于异步的锁。相对于标准库的 `std::mutex` 来说,有以下特性:

- 支持异步等待加锁
- 加锁与解锁不要求同一线程
Expand Down Expand Up @@ -50,3 +50,40 @@ _mtx.Unlock ();
```cpp
_mtx.IsLocked ();
```

## 异步信号量

异步信号量是一款适用于异步的信号量。相对于标准库的 `std::counting_semaphore` 来说,有以下特性:

- 支持异步等待获取

创建信号量:

```cpp
AsyncSemaphore _sema { 1 }; // 参数代表初始资源数
```
获取资源:
```cpp
// 尝试获取资源
bool _acq = _sema.TryAcquire ();
// 异步获取资源
co_await _mtx.Acquire ();
// 异步超时获取资源
bool _acq = co_await _mtx.Acquire (std::chrono::seconds (1));
```

释放资源:

```cpp
_mtx.Release ();
```

获知现有资源数:

```cpp
_mtx.GetResCount ();
```
77 changes: 55 additions & 22 deletions include/fv/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include <chrono>
#include <mutex>
#include <semaphore>
#include <string>
#include <functional>
#include <unordered_map>
Expand Down Expand Up @@ -79,7 +78,7 @@ struct AsyncMutex {
AsyncMutex (bool _init_locked = false): m_locked (_init_locked) {}

bool IsLocked () {
std::unique_lock _ul { m_mtx, std::defer_lock };
std::unique_lock _ul { m_mtx };
return m_locked;
}

Expand Down Expand Up @@ -142,31 +141,65 @@ struct AsyncMutex {


struct AsyncSemaphore {
AsyncSemaphore (int _init_count): m_sp (_init_count) {}
void Release () { m_sp.release (); }
bool TryAcquire () { return m_sp.try_acquire (); }
void Acquire () { m_sp.acquire (); }
Task<void> AcquireAsync () {
while (!m_sp.try_acquire ()) {
asio::steady_timer timer (co_await asio::this_coro::executor);
timer.expires_after (std::chrono::milliseconds (1));
co_await timer.async_wait (UseAwaitable);
AsyncSemaphore (size_t _init_count = 1): m_count (_init_count) {}

size_t GetResCount () {
std::unique_lock _ul { m_mtx };
return m_count;
}

bool TryAcquire () {
std::unique_lock _ul { m_mtx };
if (m_count > 0) {
--m_count;
return true;
} else {
return false;
}
}

Task<void> Acquire () {
std::unique_lock _ul { m_mtx, std::defer_lock };
while (true) {
_ul.lock ();
if (m_count > 0) {
--m_count;
co_return;
}
_ul.unlock ();
co_await _delay (std::chrono::milliseconds (1));
}
}
Task<bool> AcquireForAsync (TimeSpan _span) { co_return co_await AcquireUntilAsync (std::chrono::system_clock::now () + _span); }
Task<bool> AcquireUntilAsync (std::chrono::system_clock::time_point _until) {
while (!m_sp.try_acquire ()) {
if (std::chrono::system_clock::now () >= _until)
co_return false;
asio::steady_timer timer (co_await asio::this_coro::executor);
timer.expires_after (std::chrono::milliseconds (1));
co_await timer.async_wait (UseAwaitable);

Task<bool> Acquire (TimeSpan _timeout) {
std::unique_lock _ul { m_mtx, std::defer_lock };
auto _elapsed = std::chrono::system_clock::now () + _timeout;
while (_elapsed > std::chrono::system_clock::now ()) {
_ul.lock ();
if (m_count > 0) {
--m_count;
co_return true;
}
_ul.unlock ();
co_await _delay (std::chrono::milliseconds (1));
}
co_return true;
co_return false;
}

void Release () {
std::unique_lock _ul { m_mtx };
++m_count;
}

private:
std::counting_semaphore<> m_sp;
static Task<void> _delay (TimeSpan _dt) {
asio::steady_timer timer (co_await asio::this_coro::executor);
timer.expires_after (_dt);
co_await timer.async_wait (UseAwaitable);
}

size_t m_count;
std::mutex m_mtx;
};

struct CancelToken {
Expand Down Expand Up @@ -276,7 +309,7 @@ struct AsyncTimer {
~AsyncTimer () { Cancel (); }

Task<bool> WaitTimeoutAsync (TimeSpan _elapse) {
co_return !co_await m_sema.AcquireForAsync (_elapse);
co_return !co_await m_sema.Acquire (_elapse);
}

template<typename F>
Expand Down
6 changes: 6 additions & 0 deletions include/fv/common_funcs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
namespace fv {
inline std::string _to_lower (std::string _s) { std::transform (_s.begin (), _s.end (), _s.begin (), ::tolower); return _s; }



inline std::string _trim (std::string _s) {
size_t _start = 0, _stop = _s.size ();
while (_start < _stop) {
Expand All @@ -28,6 +30,8 @@ inline std::string _trim (std::string _s) {
return _s.substr (_start, _stop - _start);
};



inline std::string random_str (size_t _len) {
static const std::string s_chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string _str = "";
Expand Down Expand Up @@ -59,6 +63,8 @@ inline std::string percent_encode (std::string_view data) {
return ret;
}



inline std::string base64_encode (std::string_view data) {
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string ret;
Expand Down

0 comments on commit 38aa797

Please sign in to comment.