/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <atomic> #include <chrono> #include <cstddef> #include <cstdint> #include <folly/CPortability.h> #include <folly/Likely.h> #include <folly/lang/Exception.h> #include <folly/synchronization/SaturatingSemaphore.h> namespace folly { /// Similar to std::latch (C++20) but with timed waits. /// /// The latch class is a downward counter which can be used to synchronize /// threads. The value of the counter is initialized on creation. Threads may /// block on the latch until the counter is decremented to zero. There is no /// possibility to increase or reset the counter, which makes the latch a /// single-use barrier. // /// Example: /// /// const int N = 32; /// folly::Latch latch(N); /// std::vector<std::thread> threads; /// for (int i = 0; i < N; i++) { /// threads.emplace_back([&] { /// do_some_work(); /// latch.count_down(); /// }); /// } /// latch.wait(); /// /// A latch can be used to easily wait for mocked async methods in tests: /// /// ACTION_P(DecrementLatchImpl, latch) { /// latch.count_down(); /// } /// constexpr auto DecrementLatch = DecrementLatchImpl<folly::Latch&>; /// /// class MockableObject { /// public: /// MOCK_METHOD(void, someAsyncEvent, ()); /// }; /// /// TEST(TestSuite, TestFeature) { /// MockableObject mockObjA; /// MockableObject mockObjB; /// /// folly::Latch latch(5); /// /// EXPECT_CALL(mockObjA, someAsyncEvent()) /// .Times(2) /// .WillRepeatedly(DecrementLatch(latch)); // called 2 times /// /// EXPECT_CALL(mockObjB, someAsyncEvent()) /// .Times(3) /// .WillRepeatedly(DecrementLatch(latch)); // called 3 times /// /// // trigger async events /// // ... /// /// EXPECT_TRUE(latch.try_wait_for(std::chrono::seconds(60))); /// } class Latch { … }; } // namespace folly