| 74 | // needed synchronization |
| 75 | template <class TFactory> |
| 76 | void RunWaitTest(TFactory global) { |
| 77 | auto pool = MakePool(); |
| 78 | |
| 79 | const auto exception = std::make_exception_ptr(42); |
| 80 | |
| 81 | for (auto numPromises : xrange(1, 5)) { |
| 82 | for (auto loopIter : xrange(1024 * 64)) { |
| 83 | const auto numParticipants = numPromises + 1; |
| 84 | |
| 85 | TRelaxedBarrier barrier{numParticipants}; |
| 86 | |
| 87 | std::atomic<i64> started = 0; |
| 88 | std::atomic<i64> startedException = 0; |
| 89 | std::atomic<i64> completed = 0; |
| 90 | |
| 91 | TVector<TPromise<void>> promises; |
| 92 | for (auto i : xrange(numPromises)) { |
| 93 | Y_UNUSED(i); |
| 94 | promises.push_back(NewPromise()); |
| 95 | } |
| 96 | |
| 97 | const auto futures = ToFutures(promises); |
| 98 | |
| 99 | auto snapshotter = [&] { |
| 100 | return TStateSnapshot{ |
| 101 | .Started = started.load(std::memory_order_relaxed), |
| 102 | .StartedException = startedException.load(std::memory_order_relaxed), |
| 103 | .Futures = &futures, |
| 104 | }; |
| 105 | }; |
| 106 | |
| 107 | for (auto i : xrange(numPromises)) { |
| 108 | pool->SafeAddFunc([&, i] { |
| 109 | barrier.Arrive(); |
| 110 | |
| 111 | // subscribers must observe effects of this operation |
| 112 | // after .Set* |
| 113 | started.fetch_add(1, std::memory_order_relaxed); |
| 114 | |
| 115 | if ((loopIter % 4 == 0) && i == 0) { |
| 116 | startedException.fetch_add(1, std::memory_order_relaxed); |
| 117 | promises[i].SetException(exception); |
| 118 | } else { |
| 119 | promises[i].SetValue(); |
| 120 | } |
| 121 | |
| 122 | completed.fetch_add(1, std::memory_order_release); |
| 123 | }); |
| 124 | } |
| 125 | |
| 126 | pool->SafeAddFunc([&] { |
| 127 | auto local = global(snapshotter); |
| 128 | |
| 129 | barrier.Arrive(); |
| 130 | |
| 131 | local(); |
| 132 | |
| 133 | completed.fetch_add(1, std::memory_order_release); |
no test coverage detected