diff --git a/src/kdbindings/signal.h b/src/kdbindings/signal.h index 1361e1d..50b77fb 100644 --- a/src/kdbindings/signal.h +++ b/src/kdbindings/signal.h @@ -206,6 +206,14 @@ class ConnectionHandle * * The Args type parameter pack describe which value types the Signal will emit. * + * Deferred Connection: + * + * KDBindings::Signal supports deferred connections, enabling the decoupling of signal + * emission from the execution of connected slots. With deferred connections, you can + * connect slots to the Signal that are not immediately executed when the signal is emitted. + * Instead, you can evaluate these deferred connections at a later time, allowing for + * asynchronous or delayed execution of connected slots. + * * Examples: * - @ref 01-simple-connection/main.cpp * - @ref 02-signal-member/main.cpp @@ -251,7 +259,7 @@ class Signal { auto weakEvaluator = std::weak_ptr(evaluator); - auto connection = [weakEvaluator, slot](Args... args) { + auto connection = [weakEvaluator = std::move(weakEvaluator), slot](Args... args) { // Check if the ConnectionEvaluator is still alive if (auto evaluatorPtr = weakEvaluator.lock()) { auto lambda = [slot, args...]() { @@ -386,6 +394,10 @@ class Signal * * @return An instance of ConnectionHandle, that can be used to disconnect * or temporarily block the connection. + * + * @note + * The `KDBindings::Signal` class itself is not thread-safe. While the `ConnectionEvaluator` is inherently + * thread-safe, ensure that any concurrent access to this Signal is protected externally to maintain thread safety. */ ConnectionHandle connectDeferred(const std::shared_ptr &evaluator, std::function const &slot) { diff --git a/tests/signal/tst_signal.cpp b/tests/signal/tst_signal.cpp index 6876499..93d73b4 100644 --- a/tests/signal/tst_signal.cpp +++ b/tests/signal/tst_signal.cpp @@ -92,11 +92,13 @@ TEST_CASE("Signal connections") REQUIRE(connection.isActive()); signal.emit(4); + REQUIRE(val == 4); // val not changing immediately after emit connection.disconnect(); REQUIRE(!connection.isActive()); signal.emit(6); // It will not affect the result as the signal is disconnected + REQUIRE(val == 4); evaluator->evaluateDeferredConnections(); REQUIRE(val == 8); @@ -126,6 +128,7 @@ TEST_CASE("Signal connections") signal1.emit(2); signal2.emit(3); + REQUIRE(val == 4); // val not changing immediately after emit evaluator->evaluateDeferredConnections(); @@ -158,6 +161,9 @@ TEST_CASE("Signal connections") thread1.join(); thread2.join(); + + REQUIRE(val1 == 4); + REQUIRE(val2 == 4); evaluator->evaluateDeferredConnections(); @@ -178,6 +184,8 @@ TEST_CASE("Signal connections") REQUIRE(connection.isActive()); signal.emit(2); + REQUIRE(val == 4); + connection.disconnect(); evaluator->evaluateDeferredConnections(); @@ -195,6 +203,8 @@ TEST_CASE("Signal connections") }); signal.emit(2); + REQUIRE(val == 4); + evaluator->evaluateDeferredConnections(); evaluator->evaluateDeferredConnections();