C ++ 0x에 세마포어가 없습니까? 하나를 동기화하는 방법?
C ++ 0x에 세마포어가없는 것이 사실입니까? 스택 오버플로에는 세마포어 사용과 관련하여 이미 몇 가지 질문이 있습니다. 일반적으로 사용하는 경우 일부 이벤트를 기다릴 수 있습니다 (posix 세마포어).
void thread0(...)
{
doSomething0();
event1.wait();
...
}
void thread1(...)
{
doSomething1();
event1.post();
...
}
내가 뮤텍스로 그렇게한다면 :
void thread0(...)
{
doSomething0();
event1.lock(); event1.unlock();
...
}
void thread1(...)
{
event1.lock();
doSomethingth1();
event1.unlock();
...
}
문제 : 추악하고 thread1이 뮤텍스를 먼저 잠근다는 보장이 없습니다 (같은가 뮤텍스를 잠그고 잠금 해제해야 thread0과 thread1이 시작되기 전에 event1을 잠글 수도 있습니다).
부스트에는 세마포어가 내부 위의 방법 중 가장 간단한 방법은 무엇입니까?
뮤텍스와 조건 변수에서 하나를 쉽게 만들 수 있습니다.
#include <mutex>
#include <condition_variable>
class semaphore
{
private:
std::mutex mutex_;
std::condition_variable condition_;
unsigned long count_ = 0; // Initialized as locked.
public:
void notify() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
++count_;
condition_.notify_one();
}
void wait() {
std::unique_lock<decltype(mutex_)> lock(mutex_);
while(!count_) // Handle spurious wake-ups.
condition_.wait(lock);
--count_;
}
bool try_wait() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
if(count_) {
--count_;
return true;
}
return false;
}
};
Maxim Yegorushkin의 답변을 기반으로 C ++ 11 스타일로 예제를 만들려고했습니다.
#include <mutex>
#include <condition_variable>
class Semaphore {
public:
Semaphore (int count_ = 0)
: count(count_) {}
inline void notify()
{
std::unique_lock<std::mutex> lock(mtx);
count++;
cv.notify_one();
}
inline void wait()
{
std::unique_lock<std::mutex> lock(mtx);
while(count == 0){
cv.wait(lock);
}
count--;
}
private:
std::mutex mtx;
std::condition_variable cv;
int count;
};
나는 가능한 한 표준 스타일로 할 수 있는 가장 강력하고 일반적인 C ++ (11) 세마포어를 작성하기로 결정했습니다 (참고 : 일반적으로 하지 using semaphore = ...
사용하는 semaphore
것과 비슷한 이름을 사용합니다 ) :string
basic_string
template <typename Mutex, typename CondVar>
class basic_semaphore {
public:
using native_handle_type = typename CondVar::native_handle_type;
explicit basic_semaphore(size_t count = 0);
basic_semaphore(const basic_semaphore&) = delete;
basic_semaphore(basic_semaphore&&) = delete;
basic_semaphore& operator=(const basic_semaphore&) = delete;
basic_semaphore& operator=(basic_semaphore&&) = delete;
void notify();
void wait();
bool try_wait();
template<class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& d);
template<class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& t);
native_handle_type native_handle();
private:
Mutex mMutex;
CondVar mCv;
size_t mCount;
};
using semaphore = basic_semaphore<std::mutex, std::condition_variable>;
template <typename Mutex, typename CondVar>
basic_semaphore<Mutex, CondVar>::basic_semaphore(size_t count)
: mCount{count}
{}
template <typename Mutex, typename CondVar>
void basic_semaphore<Mutex, CondVar>::notify() {
std::lock_guard<Mutex> lock{mMutex};
++mCount;
mCv.notify_one();
}
template <typename Mutex, typename CondVar>
void basic_semaphore<Mutex, CondVar>::wait() {
std::unique_lock<Mutex> lock{mMutex};
mCv.wait(lock, [&]{ return mCount > 0; });
--mCount;
}
template <typename Mutex, typename CondVar>
bool basic_semaphore<Mutex, CondVar>::try_wait() {
std::lock_guard<Mutex> lock{mMutex};
if (mCount > 0) {
--mCount;
return true;
}
return false;
}
template <typename Mutex, typename CondVar>
template<class Rep, class Period>
bool basic_semaphore<Mutex, CondVar>::wait_for(const std::chrono::duration<Rep, Period>& d) {
std::unique_lock<Mutex> lock{mMutex};
auto finished = mCv.wait_for(lock, d, [&]{ return mCount > 0; });
if (finished)
--mCount;
return finished;
}
template <typename Mutex, typename CondVar>
template<class Clock, class Duration>
bool basic_semaphore<Mutex, CondVar>::wait_until(const std::chrono::time_point<Clock, Duration>& t) {
std::unique_lock<Mutex> lock{mMutex};
auto finished = mCv.wait_until(lock, t, [&]{ return mCount > 0; });
if (finished)
--mCount;
return finished;
}
template <typename Mutex, typename CondVar>
typename basic_semaphore<Mutex, CondVar>::native_handle_type basic_semaphore<Mutex, CondVar>::native_handle() {
return mCv.native_handle();
}
posix 세마포어에 따라
class semaphore
{
...
bool trywait()
{
boost::mutex::scoped_lock lock(mutex_);
if(count_)
{
--count_;
return true;
}
else
{
return false;
}
}
};
그리고 더 기본적인 연산자를 사용하여 스티칭 된 버전을 앞에 넣는 것보다 항상 편리한 추상화 수준에서 동기화를 사용하는 것이 좋습니다.
cpp11-on-multicore를 확인할 수도 있습니다. 이식 가능하고 최적의 세마포어 구현이 있습니다.
이 저장소에는 C ++ 11 스레딩을 보완하는 다른 스레딩도 포함되어 있습니다.
뮤텍스 및 조건 변수로 작업 할 수 있습니다. 뮤텍스로 독점 액세스 권한을 계속할지 아니면 다른 쪽 끝을 기다려야하는지 확인합니다. 기다릴 필요가 있으면 조건에서 기다립니다. 다른 표준가 계속할 수 결정하면 조건을 알립니다.
boost :: thread library는 복사 할 수 있는 간단한 예제 가 있습니다 (C ++ 0x 및 boost 라이브러리는 매우 유사합니다).
또한 유용한 기능 RAII 세마포 래퍼가 될 수 있습니다.
class ScopedSemaphore
{
public:
explicit ScopedSemaphore(Semaphore& sem) : m_Semaphore(sem) { m_Semaphore.Wait(); }
ScopedSemaphore(const ScopedSemaphore&) = delete;
~ScopedSemaphore() { m_Semaphore.Notify(); }
ScopedSemaphore& operator=(const ScopedSemaphore&) = delete;
private:
Semaphore& m_Semaphore;
};
다중 단일 앱의 사용 예 :
boost::ptr_vector<std::thread> threads;
Semaphore semaphore;
for (...)
{
...
auto t = new std::thread([..., &semaphore]
{
ScopedSemaphore scopedSemaphore(semaphore);
...
}
);
threads.push_back(t);
}
for (auto& t : threads)
t.join();
목록이 긴 shared_ptr 및 weak_ptr이 필요한 작업을 수행했습니다. 내 문제는 호스트의 내부 데이터와 상호 작용하기를 여러 클라이언트가 여러 것입니다. 일반적으로 호스트는 자체적으로 데이터를 업데이트하지만 클라이언트가 요청하면 호스트는 호스트 데이터에 액세스하는 클라이언트가 없을 때 업데이트를 중지해야합니다. 독점 클라이언트는 다른 클라이언트 나 호스트가 해당 호스트 데이터를 독점 액세스를 수 있습니다.
이 작업을 수행 한 방법은 만들었습니다.
struct UpdateLock
{
typedef std::shared_ptr< UpdateLock > ptr;
};
각 클라이언트에는 다음과 같은 구성원이 있습니다.
UpdateLock::ptr m_myLock;
그런 다음 호스트는 배타성을위한 weak_ptr 멤버와 비 배타적 잠금에 대한 weak_ptr 목록이 있습니다.
std::weak_ptr< UpdateLock > m_exclusiveLock;
std::list< std::weak_ptr< UpdateLock > > m_locks;
잠금을 활성화하는 기능과 호스트가 있는지 확인합니다.
UpdateLock::ptr LockUpdate( bool exclusive );
bool IsUpdateLocked( bool exclusive ) const;
LockUpdate, IsUpdateLocked 및 호스트의 업데이트 루틴에서 주기적으로 잠금을 테스트합니다. 잠금 테스트는 weak_ptr의 종료 여부를 확인하고 m_locks 목록에서 종료 된 항목을 제거하는 것만 큼 간단합니다 (호스트 업데이트에서 만 수행). 목록이 비어 있는지 확인할 수 있습니다. 동시에 클라이언트가 매달린 shared_ptr을 계속하면 자동 잠금 해제가 발생하며 클라이언트가 자동으로 파괴 될 때도 발생합니다.
(일반적으로 추가 및 삭제 전용으로 예약 됨) 대부분의 경우 LockUpdate (false)에 대한 요청, 즉 비 독점적 요청은 (! m_exclusiveLock) 동안 성공합니다. 그리고 독점에 대한 요청 인 LockUpdate (true)는 (! m_exclusiveLock) 및 (m_locks.empty ()) 둘 다일 때만 성공합니다.
배타적 잠금과 비 독점 잠금 사이를 사용하기 위해 큐를 추가 할 수 있습니다. 지금까지 충돌이 가능합니다. (대부분 실제 테스트 조건이 있습니다.)
지금까지이 필요에 잘 맞습니다. 확장 할 수있는 몇 가지 문제를 상상할 수있는 구현이 빠르며 사용자 코드가 거의 필요하지 않습니다.
누군가가 원자 버전에 관심이 있다면 여기에 구현이 있습니다. 성능은 뮤텍스 및 조건 변수 버전보다 더 좋을 예상됩니다.
class semaphore_atomic
{
public:
void notify() {
count_.fetch_add(1, std::memory_order_release);
}
void wait() {
while (true) {
int count = count_.load(std::memory_order_relaxed);
if (count > 0) {
if (count_.compare_exchange_weak(count, count-1, std::memory_order_acq_rel, std::memory_order_relaxed)) {
break;
}
}
}
}
bool try_wait() {
int count = count_.load(std::memory_order_relaxed);
if (count > 0) {
if (count_.compare_exchange_strong(count, count-1, std::memory_order_acq_rel, std::memory_order_relaxed)) {
return true;
}
}
return false;
}
private:
std::atomic_int count_{0};
};
참고 URL : https://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads
'IT' 카테고리의 다른 글
크롬의 디버거에서 일시 중지 되었습니까? (0) | 2020.07.11 |
---|---|
Vim에서 파일을 여는 단축키 (0) | 2020.07.11 |
인터페이스 빌더의 iOS 멀티 라인 레이블 (0) | 2020.07.11 |
Javascript를 사용하여 오브젝트 제거에 밑줄 (0) | 2020.07.11 |
레이크 0.9.0을 이미 활성화했지만 Gemfile에 레이크 0.8.7이 필요합니다. (0) | 2020.07.11 |