/* * Copyright (C) 2015 The Android Open Source Project * * 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. */ #include #include namespace utils { CyclicBarrier::CyclicBarrier(size_t num_threads) noexcept : m_num_threads(std::max(size_t(1), num_threads)) { } size_t CyclicBarrier::getThreadCount() const noexcept { return m_num_threads; } size_t CyclicBarrier::getWaitingThreadCount() const noexcept { std::lock_guard guard(m_lock); return m_trapped_threads; } void CyclicBarrier::reset() noexcept { std::unique_lock guard(m_lock); m_state = State::TRAP; m_trapped_threads = 0; m_released_threads = 0; guard.unlock(); // avoid threads to lock again immediately m_cv.notify_all(); } void CyclicBarrier::await() noexcept { std::unique_lock guard(m_lock); // we're releasing old threads, wait until we're done with that m_cv.wait(guard, [this]{ return m_state != State::RELEASE; }); // This is the last thread that will be trapped in the barrier if (m_trapped_threads == m_num_threads-1) { std::swap(m_released_threads, m_trapped_threads); // release currently trapped threads m_state = State::RELEASE; m_cv.notify_all(); // wait for all previously trapped threads to be released m_cv.wait(guard, [this]{ return m_released_threads == 0; }); m_state = State::TRAP; guard.unlock(); // avoid threads to lock again immediately m_cv.notify_all(); } else { ++m_trapped_threads; m_cv.wait(guard, [this]{ return m_state == State::RELEASE; }); if (--m_released_threads == 0) { // no more threads to be released, we need to notify the last one which is // waiting for the m_released_threads queue to become empty and will switch the // state back to State::TRAP. guard.unlock(); // avoid threads to lock again immediately m_cv.notify_all(); } } } } // namespace utils