From 0380cd595ee05773f78751aa7f2952b6ea105f7c Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 11 Jun 2021 10:43:00 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 6 +- .../life/operating-system-experiment/Semaphore.cpp | 78 ++++++++++++++++++++++ works/life/operating-system-experiment/Semaphore.h | 46 +++++++++++++ .../SemaphoreAvoidDataRaceDemo.cpp | 36 ++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 works/life/operating-system-experiment/Semaphore.cpp create mode 100644 works/life/operating-system-experiment/Semaphore.h create mode 100644 works/life/operating-system-experiment/SemaphoreAvoidDataRaceDemo.cpp diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 8b4617f..c8afc24 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD 17) find_package(fmt CONFIG REQUIRED) find_package(Microsoft.GSL CONFIG REQUIRED) -add_library(cru_system SHARED Thread.cpp Mutex.cpp Interlocked.cpp) +add_library(cru_system SHARED Thread.cpp Mutex.cpp Interlocked.cpp Semaphore.cpp) target_link_libraries(cru_system PUBLIC Microsoft.GSL::GSL fmt::fmt) target_compile_definitions(cru_system PUBLIC CRU_EXPORT_API) if(UNIX) @@ -27,3 +27,7 @@ target_link_libraries(mutex_avoid_data_race_demo PRIVATE cru_system) add_executable(interlocked_avoid_data_race_demo InterlockedAvoidDataRaceDemo.cpp) target_link_libraries(interlocked_avoid_data_race_demo PRIVATE cru_system) + +add_executable(semaphore_avoid_data_race_demo SemaphoreAvoidDataRaceDemo.cpp) +target_link_libraries(semaphore_avoid_data_race_demo PRIVATE cru_system) + diff --git a/works/life/operating-system-experiment/Semaphore.cpp b/works/life/operating-system-experiment/Semaphore.cpp new file mode 100644 index 0000000..e8221fd --- /dev/null +++ b/works/life/operating-system-experiment/Semaphore.cpp @@ -0,0 +1,78 @@ +#include "Semaphore.h" + +#include + +#ifndef CRU_WINDOWS +#include +#endif + +namespace cru { +Semaphore::Semaphore(unsigned init_value) { +#ifdef CRU_WINDOWS +#else + semaphore_ = std::make_unique(); + auto c = sem_init(semaphore_.get(), 0, init_value); + assert(c == 0); +#endif +} + +Semaphore::Semaphore(Semaphore &&other) +#ifdef CRU_WINDOWS +#else + : semaphore_(std::move(other.semaphore_)) +#endif +{ +} + +Semaphore &Semaphore::operator=(Semaphore &&other) { + if (this != &other) { + Destroy(); +#ifdef CRU_WINDOWS +#else + semaphore_ = std::move(other.semaphore_); +#endif + } + return *this; +} + +Semaphore::~Semaphore() { Destroy(); } + +void Semaphore::P() { Acquire(); } +void Semaphore::V() { Release(); } + +void Semaphore::Acquire() { +#ifdef CRU_WINDOWS +#else + auto c = sem_wait(semaphore_.get()); + assert(c == 0); +#endif +} + +bool Semaphore::TryAcquire() { +#ifdef CRU_WINDOWS +#else + auto c = sem_trywait(semaphore_.get()); + assert((c == 0) || (c == -1 && errno == EAGAIN)); + return c == 0 ? true : false; +#endif +} + +void Semaphore::Release() { +#ifdef CRU_WINDOWS +#else + auto c = sem_post(semaphore_.get()); + assert(c == 0); +#endif +} + +void Semaphore::Destroy() { +#ifdef CRU_WINDOWS +#else + if (semaphore_ != nullptr) { + auto c = sem_destroy(semaphore_.get()); + assert(c == 0); + semaphore_ = nullptr; + } +#endif +} +} // namespace cru \ No newline at end of file diff --git a/works/life/operating-system-experiment/Semaphore.h b/works/life/operating-system-experiment/Semaphore.h new file mode 100644 index 0000000..1d49b60 --- /dev/null +++ b/works/life/operating-system-experiment/Semaphore.h @@ -0,0 +1,46 @@ +#ifndef HEADER_SEMAPHORE_H +#define HEADER_SEMAPHORE_H + +#include "Base.h" + +#include + +#ifdef CRU_WINDOWS +#include +#else +#include +#endif + +namespace cru { +class CRU_API Semaphore { +public: + explicit Semaphore(unsigned init_value = 1); + + Semaphore(const Semaphore &other) = delete; + Semaphore &operator=(const Semaphore &other) = delete; + + Semaphore(Semaphore &&other); + Semaphore &operator=(Semaphore &&other); + + ~Semaphore(); + +public: + void P(); + void V(); + + void Acquire(); + bool TryAcquire(); + void Release(); + +private: + void Destroy(); + +private: +#ifdef CRU_WINDOWS +#else + std::unique_ptr semaphore_; +#endif +}; +} // namespace cru + +#endif \ No newline at end of file diff --git a/works/life/operating-system-experiment/SemaphoreAvoidDataRaceDemo.cpp b/works/life/operating-system-experiment/SemaphoreAvoidDataRaceDemo.cpp new file mode 100644 index 0000000..0068082 --- /dev/null +++ b/works/life/operating-system-experiment/SemaphoreAvoidDataRaceDemo.cpp @@ -0,0 +1,36 @@ +#include "Semaphore.h" +#include "Thread.h" + +#include + +int main() { + unsigned data = 0; + + cru::Semaphore semaphore; + + cru::Thread t1([&data, &semaphore] { + for (int i = 0; i < 100000; i++) { + semaphore.P(); + data += 10; + semaphore.V(); + } + }); + + cru::Thread t2([&data, &semaphore] { + for (int i = 0; i < 100000; i++) { + semaphore.P(); + data += 10; + semaphore.V(); + } + }); + + std::cout << "Created thread: " << t1.GetNativeID() << '\n'; + std::cout << "Created thread: " << t2.GetNativeID() << '\n'; + + t1.Join(); + t2.Join(); + std::cout << "Answer is " << data << ", which is " + << (data == 2000000 ? "correct" : "false") << '\n'; + + return 0; +} -- cgit v1.2.3