
Stier
Stimmt es, dass C++0x ohne Semaphore kommen wird? Es gibt bereits einige Fragen zu Stack Overflow bezüglich der Verwendung von Semaphoren. Ich benutze sie (Posix-Semaphoren) die ganze Zeit, um einen Thread auf ein Ereignis in einem anderen Thread warten zu lassen:
void thread0(...)
{
doSomething0();
event1.wait();
...
}
void thread1(...)
{
doSomething1();
event1.post();
...
}
Wenn ich das mit einem Mutex machen würde:
void thread0(...)
{
doSomething0();
event1.lock(); event1.unlock();
...
}
void thread1(...)
{
event1.lock();
doSomethingth1();
event1.unlock();
...
}
Problem: Es ist hässlich und es ist nicht garantiert, dass Thread1 den Mutex zuerst sperrt (da derselbe Thread einen Mutex sperren und entsperren sollte, können Sie event1 auch nicht sperren, bevor Thread0 und Thread1 gestartet wurden).
Da Boost auch keine Semaphoren hat, was ist der einfachste Weg, um das oben Genannte zu erreichen?

Maxim Egorushkin
Sie können ganz einfach einen aus einem Mutex und einer Bedingungsvariablen erstellen:
#include <mutex>
#include <condition_variable>
class semaphore {
std::mutex mutex_;
std::condition_variable condition_;
unsigned long count_ = 0; // Initialized as locked.
public:
void release() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
++count_;
condition_.notify_one();
}
void acquire() {
std::unique_lock<decltype(mutex_)> lock(mutex_);
while(!count_) // Handle spurious wake-ups.
condition_.wait(lock);
--count_;
}
bool try_acquire() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
if(count_) {
--count_;
return true;
}
return false;
}
};

Tsuneo Yoshioka
Basierend auf der Antwort von Maxim Yegorushkin habe ich versucht, das Beispiel im C++ 11-Stil zu erstellen.
#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;
};

David
Ich habe mich entschieden, das robusteste/generischste C++11-Semaphor zu schreiben, das ich konnte, im Stil des Standards so weit wie möglich (Anmerkung using semaphore = ...
würden Sie normalerweise nur den Namen verwenden semaphore
ähnlich wie bei normaler Verwendung string
nicht 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();
}
in Übereinstimmung mit Posix-Semaphoren, würde ich hinzufügen
class semaphore
{
...
bool trywait()
{
boost::mutex::scoped_lock lock(mutex_);
if(count_)
{
--count_;
return true;
}
else
{
return false;
}
}
};
Und ich ziehe es vor, einen Synchronisationsmechanismus auf einer bequemen Abstraktionsebene zu verwenden, anstatt immer eine zusammengesetzte Version mit einfacheren Operatoren zu kopieren und einzufügen.

einpoklum
C++20 hat endlich Semaphoren – std::counting_semaphore<max_count>
.
Diese haben (mindestens) folgende Methoden:
acquire()
(Blockierung)
try_acquire()
(nicht blockierend, kehrt sofort zurück)
try_acquire_for()
(nicht blockierend, dauert eine Dauer)
try_acquire_until()
(nicht blockierend, dauert eine Weile, bis der Versuch beendet wird)
release()
Du kannst lesen diese CppCon 2019 Präsentationsfolienoder sehen Sie sich die an Video. Es gibt auch den offiziellen Vorschlag P0514R4aber es ist möglicherweise nicht auf dem neuesten Stand von C++20.

onqtam
Sie können auch auschecken cpp11-auf-Multicore – es hat eine portable und optimale Semaphor-Implementierung.
Das Repository enthält auch andere Threading-Goodies, die das C++11-Threading ergänzen.

David Rodríguez – Dribeas
Sie können mit Mutex- und Bedingungsvariablen arbeiten. Mit dem Mutex erhalten Sie exklusiven Zugriff, prüfen, ob Sie weitermachen wollen oder auf das andere Ende warten müssen. Wenn Sie warten müssen, warten Sie in einer Bedingung. Wenn der andere Thread feststellt, dass Sie fortfahren können, signalisiert er die Bedingung.
Es gibt einen Kurzschluss Beispiel in der boost::thread-Bibliothek, die Sie höchstwahrscheinlich einfach kopieren können (die C++0x- und boost-Thread-Bibliotheken sind sehr ähnlich).
9929500cookie-checkC++0x hat keine Semaphoren? Wie synchronisiere ich Threads?yes
Verwenden Sie vielleicht die Bedingung mutex und std::promise und std::future?
– Yves
13. Dezember 2016 um 8:22 Uhr