diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-08-28 01:30:30 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-08-28 01:30:30 +0000 |
| commit | 825578aeec14e7cfb54c1b70727c4e2038c0b1ce (patch) | |
| tree | 67841fb9a30a26d4ac0fd55f08d3604a0a4b5096 /Common/interface | |
| parent | Fixed a problem with accessing variables in inactive shader stages in D3D11 b... (diff) | |
| download | DiligentCore-825578aeec14e7cfb54c1b70727c4e2038c0b1ce.tar.gz DiligentCore-825578aeec14e7cfb54c1b70727c4e2038c0b1ce.zip | |
Moved Signal class from LockHelper.h to Signal.h
Diffstat (limited to 'Common/interface')
| -rw-r--r-- | Common/interface/LockHelper.h | 93 | ||||
| -rw-r--r-- | Common/interface/RefCntAutoPtr.h | 1 | ||||
| -rw-r--r-- | Common/interface/Signal.h | 125 |
3 files changed, 125 insertions, 94 deletions
diff --git a/Common/interface/LockHelper.h b/Common/interface/LockHelper.h index b96b92ec..32ae9cf5 100644 --- a/Common/interface/LockHelper.h +++ b/Common/interface/LockHelper.h @@ -24,9 +24,6 @@ #pragma once #include <thread> -#include <mutex> -#include <condition_variable> -#include <atomic> #include "../../Platforms/interface/Atomics.h" #include "../../Platforms/Basic/interface/DebugUtilities.h" @@ -133,94 +130,4 @@ private: const LockHelper& operator = ( const LockHelper &LockHelper ); }; -class Signal -{ -public: - Signal() - { - m_SignalledValue = 0; - m_NumThreadsAwaken = 0; - } - - // http://en.cppreference.com/w/cpp/thread/condition_variable - void Trigger(bool NotifyAll = false, int SignalValue = 1) - { - // The thread that intends to modify the variable has to - // * acquire a std::mutex (typically via std::lock_guard) - // * perform the modification while the lock is held - // * execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification) - { - // std::condition_variable works only with std::unique_lock<std::mutex> - std::lock_guard<std::mutex> Lock(m_Mutex); - VERIFY(SignalValue != 0, "Signal value must not be 0"); - VERIFY(m_SignalledValue == 0 && m_NumThreadsAwaken == 0, "Not all threads have been awaken since the signal was triggered last time, or the signal has not been reset"); - m_SignalledValue = SignalValue; - } - // Unlocking is done before notifying, to avoid waking up the waiting - // thread only to block again (see notify_one for details) - if(NotifyAll) - m_CondVar.notify_all(); - else - m_CondVar.notify_one(); - } - - // WARNING! - // If multiple threads are waiting for a signal in an infinite loop, - // autoresetting the signal does not guarantee that one thread cannot - // go through the loop twice. In this case, every thread must wait for its - // own auto-reset signal or the threads must be blocked by another signal - - int Wait(bool AutoReset = false, int NumThreadsWaiting = 0) - { - // Any thread that intends to wait on std::condition_variable has to - // * acquire a std::unique_lock<std::mutex>, on the SAME MUTEX as used to protect the shared variable - // * execute wait, wait_for, or wait_until. The wait operations atomically release the mutex - // and suspend the execution of the thread. - // * When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, - // the thread is awakened, and the mutex is atomically reacquired: - // - The thread should then check the condition and resume waiting if the wake up was spurious. - std::unique_lock<std::mutex> Lock(m_Mutex); - // It is safe to check m_SignalledValue since we are holding - // the mutex - if(m_SignalledValue == 0) - { - m_CondVar.wait(Lock, [&] {return m_SignalledValue != 0;} ); - } - int SignalledValue = m_SignalledValue; - // Count the number of threads awaken while holding the mutex - ++m_NumThreadsAwaken; - if (AutoReset) - { - VERIFY(NumThreadsWaiting > 0, "Number of waiting threads must not be 0 when auto resetting the signal"); - // Reset the signal while holding the mutex. If Trigger() is executed by another - // thread, it will wait until we release the mutex - if(m_NumThreadsAwaken == NumThreadsWaiting) - { - m_SignalledValue = 0; - m_NumThreadsAwaken = 0; - } - } - return SignalledValue; - } - - void Reset() - { - std::lock_guard<std::mutex> Lock(m_Mutex); - m_SignalledValue = 0; - m_NumThreadsAwaken = 0; - } - - bool IsTriggered()const { return m_SignalledValue != 0; } - -private: - - std::mutex m_Mutex; - std::condition_variable m_CondVar; - std::atomic_int m_SignalledValue; - std::atomic_int m_NumThreadsAwaken; - - Signal(const Signal&) = delete; - Signal& operator = (const Signal&) = delete; -}; - } diff --git a/Common/interface/RefCntAutoPtr.h b/Common/interface/RefCntAutoPtr.h index 5ef3bfe6..6a826c27 100644 --- a/Common/interface/RefCntAutoPtr.h +++ b/Common/interface/RefCntAutoPtr.h @@ -26,7 +26,6 @@ #include "../../Primitives/interface/Object.h" #include "../../Platforms/Basic/interface/DebugUtilities.h" #include "../../Platforms/interface/Atomics.h" -#include "LockHelper.h" #include "ValidatedCast.h" #include "RefCountedObjectImpl.h" diff --git a/Common/interface/Signal.h b/Common/interface/Signal.h new file mode 100644 index 00000000..548ef22b --- /dev/null +++ b/Common/interface/Signal.h @@ -0,0 +1,125 @@ +/* Copyright 2015-2018 Egor Yusov + * + * 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include <mutex> +#include <condition_variable> +#include <atomic> + +#include "../../Platforms/Basic/interface/DebugUtilities.h" + +namespace ThreadingTools +{ + +class Signal +{ +public: + Signal() + { + m_SignalledValue = 0; + m_NumThreadsAwaken = 0; + } + + // http://en.cppreference.com/w/cpp/thread/condition_variable + void Trigger(bool NotifyAll = false, int SignalValue = 1) + { + // The thread that intends to modify the variable has to + // * acquire a std::mutex (typically via std::lock_guard) + // * perform the modification while the lock is held + // * execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification) + { + // std::condition_variable works only with std::unique_lock<std::mutex> + std::lock_guard<std::mutex> Lock(m_Mutex); + VERIFY(SignalValue != 0, "Signal value must not be 0"); + VERIFY(m_SignalledValue == 0 && m_NumThreadsAwaken == 0, "Not all threads have been awaken since the signal was triggered last time, or the signal has not been reset"); + m_SignalledValue = SignalValue; + } + // Unlocking is done before notifying, to avoid waking up the waiting + // thread only to block again (see notify_one for details) + if(NotifyAll) + m_CondVar.notify_all(); + else + m_CondVar.notify_one(); + } + + // WARNING! + // If multiple threads are waiting for a signal in an infinite loop, + // autoresetting the signal does not guarantee that one thread cannot + // go through the loop twice. In this case, every thread must wait for its + // own auto-reset signal or the threads must be blocked by another signal + + int Wait(bool AutoReset = false, int NumThreadsWaiting = 0) + { + // Any thread that intends to wait on std::condition_variable has to + // * acquire a std::unique_lock<std::mutex>, on the SAME MUTEX as used to protect the shared variable + // * execute wait, wait_for, or wait_until. The wait operations atomically release the mutex + // and suspend the execution of the thread. + // * When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, + // the thread is awakened, and the mutex is atomically reacquired: + // - The thread should then check the condition and resume waiting if the wake up was spurious. + std::unique_lock<std::mutex> Lock(m_Mutex); + // It is safe to check m_SignalledValue since we are holding + // the mutex + if(m_SignalledValue == 0) + { + m_CondVar.wait(Lock, [&] {return m_SignalledValue != 0;} ); + } + int SignalledValue = m_SignalledValue; + // Count the number of threads awaken while holding the mutex + ++m_NumThreadsAwaken; + if (AutoReset) + { + VERIFY(NumThreadsWaiting > 0, "Number of waiting threads must not be 0 when auto resetting the signal"); + // Reset the signal while holding the mutex. If Trigger() is executed by another + // thread, it will wait until we release the mutex + if(m_NumThreadsAwaken == NumThreadsWaiting) + { + m_SignalledValue = 0; + m_NumThreadsAwaken = 0; + } + } + return SignalledValue; + } + + void Reset() + { + std::lock_guard<std::mutex> Lock(m_Mutex); + m_SignalledValue = 0; + m_NumThreadsAwaken = 0; + } + + bool IsTriggered()const { return m_SignalledValue != 0; } + +private: + + std::mutex m_Mutex; + std::condition_variable m_CondVar; + std::atomic_int m_SignalledValue; + std::atomic_int m_NumThreadsAwaken; + + Signal(const Signal&) = delete; + Signal& operator = (const Signal&) = delete; +}; + +} |
