From ef593ba2d445af515214d63bfd3942be9d673467 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:12:25 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Mutex.cpp | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 works/life/operating-system-experiment/Mutex.cpp (limited to 'works/life/operating-system-experiment/Mutex.cpp') diff --git a/works/life/operating-system-experiment/Mutex.cpp b/works/life/operating-system-experiment/Mutex.cpp new file mode 100644 index 0000000..6a91885 --- /dev/null +++ b/works/life/operating-system-experiment/Mutex.cpp @@ -0,0 +1,78 @@ +#include "Mutex.h" + +#include +#include + +#ifndef CRU_WINDOWS +#include +#endif + +namespace cru { +Mutex::Mutex() { +#ifdef CRU_WINDOWS +#else + mutex_ = std::make_unique(); + + auto c = pthread_mutex_init(mutex_.get(), nullptr); + assert(c == 0); +#endif +} + +Mutex::Mutex(Mutex &&other) +#ifdef CRU_WINDOWS +#else + : mutex_(std::move(other.mutex_)) +#endif +{ +} + +Mutex &Mutex::operator=(Mutex &&other) { + if (this != &other) { + Destroy(); + mutex_ = std::move(other.mutex_); + } + return *this; +} + +Mutex::~Mutex() { Destroy(); } + +void Mutex::Lock() { +#ifdef CRU_WINDOWS +#else + assert(mutex_); + auto c = pthread_mutex_lock(mutex_.get()); + assert(c == 0); +#endif +} + +bool Mutex::TryLock() { +#ifdef CRU_WINDOWS +#else + assert(mutex_); + auto c = pthread_mutex_trylock(mutex_.get()); + assert(c == 0 || c == EBUSY); + return c == 0 ? true : false; +#endif +} + +void Mutex::Unlock() { +#ifdef CRU_WINDOWS +#else + assert(mutex_); + auto c = pthread_mutex_unlock(mutex_.get()); + assert(c == 0); +#endif +} + +void Mutex::Destroy() { +#ifdef CRU_WINDOWS +#else + if (mutex_ != nullptr) { + auto c = pthread_mutex_destroy(mutex_.get()); + assert(c); + mutex_ = nullptr; + } +#endif +} + +} // namespace cru -- cgit v1.2.3 From f532667d936500f50447d63333544f603ec06137 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:35:29 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 3 ++ .../operating-system-experiment/DataRaceDemo.cpp | 2 +- works/life/operating-system-experiment/Mutex.cpp | 23 +++++++++++- works/life/operating-system-experiment/Mutex.h | 1 + .../MutexAvoidDataRaceDemo.cpp | 42 ++++++++++++++++++++++ works/life/operating-system-experiment/Thread.cpp | 5 ++- 6 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 works/life/operating-system-experiment/MutexAvoidDataRaceDemo.cpp (limited to 'works/life/operating-system-experiment/Mutex.cpp') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 806ec74..139d2ba 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -21,3 +21,6 @@ target_link_libraries(main PRIVATE cru_system) add_executable(data_race_demo DataRaceDemo.cpp) target_link_libraries(data_race_demo PRIVATE cru_system) + +add_executable(mutex_avoid_data_race_demo MutexAvoidDataRaceDemo.cpp) +target_link_libraries(mutex_avoid_data_race_demo PRIVATE cru_system) diff --git a/works/life/operating-system-experiment/DataRaceDemo.cpp b/works/life/operating-system-experiment/DataRaceDemo.cpp index 9589eb3..a2f98d9 100644 --- a/works/life/operating-system-experiment/DataRaceDemo.cpp +++ b/works/life/operating-system-experiment/DataRaceDemo.cpp @@ -21,7 +21,7 @@ int main() { t1.Join(); t2.Join(); std::cout << "Answer is " << data << ", which is " - << (data == 200000 ? "correct" : "false") << '\n'; + << (data == 2000000 ? "correct" : "false") << '\n'; return 0; } diff --git a/works/life/operating-system-experiment/Mutex.cpp b/works/life/operating-system-experiment/Mutex.cpp index 6a91885..b7d0cb6 100644 --- a/works/life/operating-system-experiment/Mutex.cpp +++ b/works/life/operating-system-experiment/Mutex.cpp @@ -1,7 +1,6 @@ #include "Mutex.h" #include -#include #ifndef CRU_WINDOWS #include @@ -10,6 +9,8 @@ namespace cru { Mutex::Mutex() { #ifdef CRU_WINDOWS + handle_ = CreateMutexW(nullptr, FALSE, nullptr); + assert(handle_); #else mutex_ = std::make_unique(); @@ -20,16 +21,25 @@ Mutex::Mutex() { Mutex::Mutex(Mutex &&other) #ifdef CRU_WINDOWS + : handle_(other.handle_) #else : mutex_(std::move(other.mutex_)) #endif { +#ifdef CRU_WINDOWS + other.handle_ = nullptr; +#endif } Mutex &Mutex::operator=(Mutex &&other) { if (this != &other) { Destroy(); +#ifdef CRU_WINDOWS + handle_ = other.handle_; + other.handle_ = nullptr; +#else mutex_ = std::move(other.mutex_); +#endif } return *this; } @@ -38,6 +48,8 @@ Mutex::~Mutex() { Destroy(); } void Mutex::Lock() { #ifdef CRU_WINDOWS + auto c = WaitForSingleObject(handle_, INFINITE); + assert(c == WAIT_OBJECT_0); #else assert(mutex_); auto c = pthread_mutex_lock(mutex_.get()); @@ -47,6 +59,9 @@ void Mutex::Lock() { bool Mutex::TryLock() { #ifdef CRU_WINDOWS + auto c = WaitForSingleObject(handle_, 0); + assert(c == WAIT_OBJECT_0 || c == WAIT_TIMEOUT); + return c == WAIT_OBJECT_0 ? true : false; #else assert(mutex_); auto c = pthread_mutex_trylock(mutex_.get()); @@ -57,6 +72,8 @@ bool Mutex::TryLock() { void Mutex::Unlock() { #ifdef CRU_WINDOWS + auto c = ReleaseMutex(handle_); + assert(c); #else assert(mutex_); auto c = pthread_mutex_unlock(mutex_.get()); @@ -66,6 +83,10 @@ void Mutex::Unlock() { void Mutex::Destroy() { #ifdef CRU_WINDOWS + if (handle_ != nullptr) { + auto c = CloseHandle(handle_); + assert(c); + } #else if (mutex_ != nullptr) { auto c = pthread_mutex_destroy(mutex_.get()); diff --git a/works/life/operating-system-experiment/Mutex.h b/works/life/operating-system-experiment/Mutex.h index 163d9ca..d561f1a 100644 --- a/works/life/operating-system-experiment/Mutex.h +++ b/works/life/operating-system-experiment/Mutex.h @@ -35,6 +35,7 @@ private: private: #ifdef CRU_WINDOWS + HANDLE handle_; #else std::unique_ptr mutex_; #endif diff --git a/works/life/operating-system-experiment/MutexAvoidDataRaceDemo.cpp b/works/life/operating-system-experiment/MutexAvoidDataRaceDemo.cpp new file mode 100644 index 0000000..81a7aa1 --- /dev/null +++ b/works/life/operating-system-experiment/MutexAvoidDataRaceDemo.cpp @@ -0,0 +1,42 @@ +#include "Mutex.h" +#include "Thread.h" + +#include + +int main() { + + unsigned data = 0; + cru::Mutex mutex; + mutex.Lock(); + + cru::Thread t1([&data, &mutex] { + for (int i = 0; i < 100000; i++) { + mutex.Lock(); + data += 10; + //std::cout << "Data is now: " << data << '\n'; + mutex.Unlock(); + } + }); + + cru::Thread t2([&data, &mutex] { + for (int i = 0; i < 100000; i++) { + mutex.Lock(); + data += 10; + //std::cout << "Data is now: " << data << '\n'; + mutex.Unlock(); + } + }); + + std::cout << "Created thread: " << t1.GetNativeID() << '\n'; + std::cout << "Created thread: " << t2.GetNativeID() << '\n'; + + mutex.Unlock(); + + t1.Join(); + t2.Join(); + + std::cout << "Answer is " << data << ", which is " + << (data == 2000000 ? "correct" : "false") << '\n'; + + return 0; +} diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index 7e3c784..a5f526d 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -112,7 +112,10 @@ void Thread::Destroy() noexcept { joined_ = false; #ifdef CRU_WINDOWS thread_id_ = 0; - thread_handle_ = nullptr; + if (thread_handle_ != nullptr) { + CloseHandle(thread_handle_); + thread_handle_ = nullptr; + } #else thread_ = nullptr; #endif -- cgit v1.2.3 From bfd0f33af41ac2d5f26d597eac80070911c945a5 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:36:27 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Mutex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'works/life/operating-system-experiment/Mutex.cpp') diff --git a/works/life/operating-system-experiment/Mutex.cpp b/works/life/operating-system-experiment/Mutex.cpp index b7d0cb6..4d360f1 100644 --- a/works/life/operating-system-experiment/Mutex.cpp +++ b/works/life/operating-system-experiment/Mutex.cpp @@ -90,7 +90,7 @@ void Mutex::Destroy() { #else if (mutex_ != nullptr) { auto c = pthread_mutex_destroy(mutex_.get()); - assert(c); + assert(c == 0); mutex_ = nullptr; } #endif -- cgit v1.2.3 From fabd9692c49bad9f4f2858315f2a16501ad45d21 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 11 Jun 2021 11:02:41 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Mutex.cpp | 1 + works/life/operating-system-experiment/Semaphore.cpp | 20 ++++++++++++++++++++ works/life/operating-system-experiment/Semaphore.h | 1 + works/life/operating-system-experiment/Thread.cpp | 3 ++- 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'works/life/operating-system-experiment/Mutex.cpp') diff --git a/works/life/operating-system-experiment/Mutex.cpp b/works/life/operating-system-experiment/Mutex.cpp index 4d360f1..8acfdc5 100644 --- a/works/life/operating-system-experiment/Mutex.cpp +++ b/works/life/operating-system-experiment/Mutex.cpp @@ -86,6 +86,7 @@ void Mutex::Destroy() { if (handle_ != nullptr) { auto c = CloseHandle(handle_); assert(c); + handle_ = nullptr; } #else if (mutex_ != nullptr) { diff --git a/works/life/operating-system-experiment/Semaphore.cpp b/works/life/operating-system-experiment/Semaphore.cpp index e8221fd..aceef4d 100644 --- a/works/life/operating-system-experiment/Semaphore.cpp +++ b/works/life/operating-system-experiment/Semaphore.cpp @@ -9,6 +9,8 @@ namespace cru { Semaphore::Semaphore(unsigned init_value) { #ifdef CRU_WINDOWS + handle_ = CreateSemaphoreW(nullptr, init_value, 100, nullptr); + assert(handle_); #else semaphore_ = std::make_unique(); auto c = sem_init(semaphore_.get(), 0, init_value); @@ -18,16 +20,22 @@ Semaphore::Semaphore(unsigned init_value) { Semaphore::Semaphore(Semaphore &&other) #ifdef CRU_WINDOWS + : handle_(other.handle_) #else : semaphore_(std::move(other.semaphore_)) #endif { +#ifdef CRU_WINDOWS + other.handle_ = nullptr; +#endif } Semaphore &Semaphore::operator=(Semaphore &&other) { if (this != &other) { Destroy(); #ifdef CRU_WINDOWS + handle_ = other.handle_; + other.handle_ = nullptr; #else semaphore_ = std::move(other.semaphore_); #endif @@ -42,6 +50,8 @@ void Semaphore::V() { Release(); } void Semaphore::Acquire() { #ifdef CRU_WINDOWS + auto c = WaitForSingleObject(handle_, INFINITE); + assert(c == WAIT_OBJECT_0); #else auto c = sem_wait(semaphore_.get()); assert(c == 0); @@ -50,6 +60,9 @@ void Semaphore::Acquire() { bool Semaphore::TryAcquire() { #ifdef CRU_WINDOWS + auto c = WaitForSingleObject(handle_, 0); + assert(c == WAIT_OBJECT_0 || c == WAIT_TIMEOUT); + return c == WAIT_OBJECT_0 ? true : false; #else auto c = sem_trywait(semaphore_.get()); assert((c == 0) || (c == -1 && errno == EAGAIN)); @@ -59,6 +72,8 @@ bool Semaphore::TryAcquire() { void Semaphore::Release() { #ifdef CRU_WINDOWS + auto c = ReleaseSemaphore(handle_, 1, nullptr); + assert(c); #else auto c = sem_post(semaphore_.get()); assert(c == 0); @@ -67,6 +82,11 @@ void Semaphore::Release() { void Semaphore::Destroy() { #ifdef CRU_WINDOWS + if (handle_ != nullptr) { + auto c = CloseHandle(handle_); + assert(c); + handle_ = nullptr; + } #else if (semaphore_ != nullptr) { auto c = sem_destroy(semaphore_.get()); diff --git a/works/life/operating-system-experiment/Semaphore.h b/works/life/operating-system-experiment/Semaphore.h index 1d49b60..430c036 100644 --- a/works/life/operating-system-experiment/Semaphore.h +++ b/works/life/operating-system-experiment/Semaphore.h @@ -37,6 +37,7 @@ private: private: #ifdef CRU_WINDOWS + HANDLE handle_ = nullptr; #else std::unique_ptr semaphore_; #endif diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index 657c69f..0bc4c18 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -113,7 +113,8 @@ void Thread::Destroy() noexcept { #ifdef CRU_WINDOWS thread_id_ = 0; if (thread_handle_ != nullptr) { - CloseHandle(thread_handle_); + auto c = CloseHandle(thread_handle_); + assert(c); thread_handle_ = nullptr; } #else -- cgit v1.2.3