Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2104e54

Browse files
committed
Merge branch 'master' of github.com:lewissbaker/cppcoro into clang
# Conflicts: # tools/cake
2 parents 7db2848 + 2af1b18 commit 2104e54

11 files changed

+982
-4
lines changed

README.md

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ These include:
1414
* Awaitable Types
1515
* `single_consumer_event`
1616
* `async_mutex`
17-
* `async_manual_reset_event` (coming)
17+
* `async_manual_reset_event`
18+
* `async_auto_reset_event`
1819
* Functions
1920
* `when_all()` (coming)
2021
* Cancellation
@@ -753,6 +754,156 @@ cppcoro::task<> add_item(std::string value)
753754
}
754755
```
755756

757+
## `async_manual_reset_event`
758+
759+
A manual-reset event is a coroutine/thread-synchronisation primitive that allows one or more threads
760+
to wait until the event is signalled by a thread that calls `set()`.
761+
762+
The event is in one of two states; *'set'* and *'not set'*.
763+
764+
If the event is in the *'set'* state when a coroutine awaits the event then the coroutine
765+
continues without suspending. However if the coroutine is in the *'not set'* state then the
766+
coroutine is suspended until some thread subsequently calls the `set()` method.
767+
768+
Any threads that were suspended while waiting for the event to become *'set'* will be resumed
769+
inside the next call to `set()` by some thread.
770+
771+
Note that you must ensure that no coroutines are awaiting a *'not set'* event when the
772+
event is destructed as they will not be resumed.
773+
774+
Example:
775+
```c++
776+
cppcoro::async_manual_reset_event event;
777+
std::string value;
778+
779+
void producer()
780+
{
781+
value = get_some_string_value();
782+
783+
// Publish a value by setting the event.
784+
event.set();
785+
}
786+
787+
// Can be called many times to create many tasks.
788+
// All consumer tasks will wait until value has been published.
789+
cppcoro::task<> consumer()
790+
{
791+
// Wait until value has been published by awaiting event.
792+
co_await event;
793+
794+
consume_value(value);
795+
}
796+
```
797+
798+
API Summary:
799+
```c++
800+
namespace cppcoro
801+
{
802+
class async_manual_reset_event_operation;
803+
804+
class async_manual_reset_event
805+
{
806+
public:
807+
async_manual_reset_event(bool initiallySet = false) noexcept;
808+
~async_manual_reset_event();
809+
810+
async_manual_reset_event(const async_manual_reset_event&) = delete;
811+
async_manual_reset_event(async_manual_reset_event&&) = delete;
812+
async_manual_reset_event& operator=(const async_manual_reset_event&) = delete;
813+
async_manual_reset_event& operator=(async_manual_reset_event&&) = delete;
814+
815+
// Wait until the event becomes set.
816+
<unspecified> operator co_await() const noexcept;
817+
818+
bool is_set() const noexcept;
819+
820+
void set() noexcept;
821+
822+
void reset() noexcept;
823+
824+
};
825+
826+
class async_manual_reset_event
827+
{
828+
public:
829+
async_manual_reset_event_operation(async_manual_reset_event& event) noexcept;
830+
831+
bool await_ready() const noexcept;
832+
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
833+
void await_resume() const noexcept;
834+
};
835+
}
836+
```
837+
838+
## `async_auto_reset_event`
839+
840+
An auto-reset event is a coroutine/thread-synchronisation primitive that allows one or more threads
841+
to wait until the event is signalled by a thread by calling `set()`.
842+
843+
Once a coroutine that is awaiting the event is released by either a prior or subsequent call to `set()`
844+
the event is automatically reset back to the 'not set' state.
845+
846+
API Summary:
847+
```c++
848+
// <cppcoro/async_auto_reset_event.hpp>
849+
namespace cppcoro
850+
{
851+
class async_auto_reset_event_operation;
852+
853+
class async_auto_reset_event
854+
{
855+
public:
856+
857+
async_auto_reset_event(bool initiallySet = false) noexcept;
858+
859+
~async_auto_reset_event();
860+
861+
async_auto_reset_event(const async_auto_reset_event&) = delete;
862+
async_auto_reset_event(async_auto_reset_event&&) = delete;
863+
async_auto_reset_event& operator=(const async_auto_reset_event&) = delete;
864+
async_auto_reset_event& operator=(async_auto_reset_event&&) = delete;
865+
866+
// Wait for the event to enter the 'set' state.
867+
//
868+
// If the event is already 'set' then the event is set to the 'not set'
869+
// state and the awaiting coroutine continues without suspending.
870+
// Otherwise, the coroutine is suspended and later resumed when some
871+
// thread calls 'set()'.
872+
//
873+
// Note that the coroutine may be resumed inside a call to 'set()'
874+
// or inside another thread's call to 'operator co_await()'.
875+
async_auto_reset_event_operation operator co_await() const noexcept;
876+
877+
// Set the state of the event to 'set'.
878+
//
879+
// If there are pending coroutines awaiting the event then one
880+
// pending coroutine is resumed and the state is immediately
881+
// set back to the 'not set' state.
882+
//
883+
// This operation is a no-op if the event was already 'set'.
884+
void set() noexcept;
885+
886+
// Set the state of the event to 'not-set'.
887+
//
888+
// This is a no-op if the state was already 'not set'.
889+
void reset() noexcept;
890+
891+
};
892+
893+
class async_auto_reset_event_operation
894+
{
895+
public:
896+
explicit async_auto_reset_event_operation(async_auto_reset_event& event) noexcept;
897+
async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept;
898+
899+
bool await_ready() const noexcept;
900+
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
901+
void await_resume() const noexcept;
902+
903+
};
904+
}
905+
```
906+
756907
## `cancellation_token`
757908

758909
A `cancellation_token` is a value that can be passed to a function that allows the caller to subsequently communicate a request to cancel the operation to that function.

config.cake

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,15 @@ if cake.system.isWindows() or cake.system.isCygwin():
6767

6868
for arch in ("x64", "x86"):
6969
try:
70-
from cake.library.compilers.msvc import getVisualStudio2017Compiler
70+
from cake.library.compilers.msvc import getVisualStudio2017Compiler, findMsvc2017InstallDir
71+
if nugetPath:
72+
vcInstallDir = cake.path.join(nugetPath, 'lib', 'native')
73+
else:
74+
vcInstallDir = str(findMsvc2017InstallDir(targetArchitecture=arch, allowPreRelease=True))
7175
compiler = getVisualStudio2017Compiler(
7276
configuration,
7377
targetArchitecture=arch,
74-
vcInstallDir=cake.path.join(nugetPath, 'lib', 'native') if nugetPath else None,
78+
vcInstallDir=vcInstallDir,
7579
)
7680

7781
msvcVariant = baseVariant.clone(
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// Copyright (c) Lewis Baker
3+
// Licenced under MIT license. See LICENSE.txt for details.
4+
///////////////////////////////////////////////////////////////////////////////
5+
#ifndef CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED
6+
#define CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED
7+
8+
#include <experimental/coroutine>
9+
#include <atomic>
10+
#include <cstdint>
11+
12+
namespace cppcoro
13+
{
14+
class async_auto_reset_event_operation;
15+
16+
/// An async auto-reset event is a coroutine synchronisation abstraction
17+
/// that allows one or more coroutines to wait until some thread calls
18+
/// set() on the event.
19+
///
20+
/// When a coroutine awaits a 'set' event the event is automatically
21+
/// reset back to the 'not set' state, thus the name 'auto reset' event.
22+
class async_auto_reset_event
23+
{
24+
public:
25+
26+
/// Initialise the event to either 'set' or 'not set' state.
27+
async_auto_reset_event(bool initiallySet = false) noexcept;
28+
29+
~async_auto_reset_event();
30+
31+
/// Wait for the event to enter the 'set' state.
32+
///
33+
/// If the event is already 'set' then the event is set to the 'not set'
34+
/// state and the awaiting coroutine continues without suspending.
35+
/// Otherwise, the coroutine is suspended and later resumed when some
36+
/// thread calls 'set()'.
37+
///
38+
/// Note that the coroutine may be resumed inside a call to 'set()'
39+
/// or inside another thread's call to 'operator co_await()'.
40+
async_auto_reset_event_operation operator co_await() const noexcept;
41+
42+
/// Set the state of the event to 'set'.
43+
///
44+
/// If there are pending coroutines awaiting the event then one
45+
/// pending coroutine is resumed and the state is immediately
46+
/// set back to the 'not set' state.
47+
///
48+
/// This operation is a no-op if the event was already 'set'.
49+
void set() noexcept;
50+
51+
/// Set the state of the event to 'not-set'.
52+
///
53+
/// This is a no-op if the state was already 'not set'.
54+
void reset() noexcept;
55+
56+
private:
57+
58+
friend class async_auto_reset_event_operation;
59+
60+
void resume_waiters(std::uint64_t initialState) const noexcept;
61+
62+
// Bits 0-31 - Set count
63+
// Bits 32-63 - Waiter count
64+
mutable std::atomic<std::uint64_t> m_state;
65+
66+
mutable std::atomic<async_auto_reset_event_operation*> m_newWaiters;
67+
68+
mutable async_auto_reset_event_operation* m_waiters;
69+
70+
};
71+
72+
class async_auto_reset_event_operation
73+
{
74+
public:
75+
76+
async_auto_reset_event_operation() noexcept;
77+
78+
explicit async_auto_reset_event_operation(const async_auto_reset_event& event) noexcept;
79+
80+
async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept;
81+
82+
bool await_ready() const noexcept { return m_event == nullptr; }
83+
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
84+
void await_resume() const noexcept {}
85+
86+
private:
87+
88+
friend class async_auto_reset_event;
89+
90+
const async_auto_reset_event* m_event;
91+
async_auto_reset_event_operation* m_next;
92+
std::experimental::coroutine_handle<> m_awaiter;
93+
std::atomic<std::uint32_t> m_refCount;
94+
95+
};
96+
}
97+
98+
#endif
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// Copyright (c) Lewis Baker
3+
// Licenced under MIT license. See LICENSE.txt for details.
4+
///////////////////////////////////////////////////////////////////////////////
5+
#ifndef CPPCORO_ASYNC_MANUAL_RESET_EVENT_HPP_INCLUDED
6+
#define CPPCORO_ASYNC_MANUAL_RESET_EVENT_HPP_INCLUDED
7+
8+
#include <experimental/coroutine>
9+
#include <atomic>
10+
#include <cstdint>
11+
12+
namespace cppcoro
13+
{
14+
class async_manual_reset_event_operation;
15+
16+
/// An async manual-reset event is a coroutine synchronisation abstraction
17+
/// that allows one or more coroutines to wait until some thread calls
18+
/// set() on the event.
19+
///
20+
/// When a coroutine awaits a 'set' event the coroutine continues without
21+
/// suspending. Otherwise, if it awaits a 'not set' event the coroutine is
22+
/// suspended and is later resumed inside the call to 'set()'.
23+
///
24+
/// \seealso async_auto_reset_event
25+
class async_manual_reset_event
26+
{
27+
public:
28+
29+
/// Initialise the event to either 'set' or 'not set' state.
30+
///
31+
/// \param initiallySet
32+
/// If 'true' then initialises the event to the 'set' state, otherwise
33+
/// initialises the event to the 'not set' state.
34+
async_manual_reset_event(bool initiallySet = false) noexcept;
35+
36+
~async_manual_reset_event();
37+
38+
/// Wait for the event to enter the 'set' state.
39+
///
40+
/// If the event is already 'set' then the coroutine continues without
41+
/// suspending.
42+
///
43+
/// Otherwise, the coroutine is suspended and later resumed when some
44+
/// thread calls 'set()'. The coroutine will be resumed inside the next
45+
/// call to 'set()'.
46+
async_manual_reset_event_operation operator co_await() const noexcept;
47+
48+
/// Query if the event is currently in the 'set' state.
49+
bool is_set() const noexcept;
50+
51+
/// Set the state of the event to 'set'.
52+
///
53+
/// If there are pending coroutines awaiting the event then all
54+
/// pending coroutines are resumed within this call.
55+
/// Any coroutines that subsequently await the event will continue
56+
/// without suspending.
57+
///
58+
/// This operation is a no-op if the event was already 'set'.
59+
void set() noexcept;
60+
61+
/// Set the state of the event to 'not-set'.
62+
///
63+
/// Any coroutines that subsequently await the event will suspend
64+
/// until some thread calls 'set()'.
65+
///
66+
/// This is a no-op if the state was already 'not set'.
67+
void reset() noexcept;
68+
69+
private:
70+
71+
friend class async_manual_reset_event_operation;
72+
73+
// This variable has 3 states:
74+
// - this - The state is 'set'.
75+
// - nullptr - The state is 'not set' with no waiters.
76+
// - other - The state is 'not set'.
77+
// Points to an 'async_manual_reset_event_operation' that is
78+
// the head of a linked-list of waiters.
79+
mutable std::atomic<void*> m_state;
80+
81+
};
82+
83+
class async_manual_reset_event_operation
84+
{
85+
public:
86+
87+
explicit async_manual_reset_event_operation(const async_manual_reset_event& event) noexcept;
88+
89+
bool await_ready() const noexcept;
90+
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
91+
void await_resume() const noexcept {}
92+
93+
private:
94+
95+
friend class async_manual_reset_event;
96+
97+
const async_manual_reset_event& m_event;
98+
async_manual_reset_event_operation* m_next;
99+
std::experimental::coroutine_handle<> m_awaiter;
100+
101+
};
102+
}
103+
104+
#endif

0 commit comments

Comments
 (0)