From d42dfdf4b903763997d47b6e2214c2ce33b9bf8e Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 9 Jun 2021 21:59:17 +0800 Subject: import(life): Add operating system experiement. --- works/life/operating-system-experiment/.gitignore | 5 ++ works/life/operating-system-experiment/Base.h | 22 +++++++ .../operating-system-experiment/CMakeLists.txt | 17 ++++++ works/life/operating-system-experiment/Thread.cpp | 67 +++++++++++++++++++++ works/life/operating-system-experiment/Thread.h | 68 ++++++++++++++++++++++ works/life/operating-system-experiment/main.cpp | 16 +++++ 6 files changed, 195 insertions(+) create mode 100644 works/life/operating-system-experiment/.gitignore create mode 100644 works/life/operating-system-experiment/Base.h create mode 100644 works/life/operating-system-experiment/CMakeLists.txt create mode 100644 works/life/operating-system-experiment/Thread.cpp create mode 100644 works/life/operating-system-experiment/Thread.h create mode 100644 works/life/operating-system-experiment/main.cpp (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/.gitignore b/works/life/operating-system-experiment/.gitignore new file mode 100644 index 0000000..502724c --- /dev/null +++ b/works/life/operating-system-experiment/.gitignore @@ -0,0 +1,5 @@ +*.exe +*.pdb +.cache +build +compile_commands.json \ No newline at end of file diff --git a/works/life/operating-system-experiment/Base.h b/works/life/operating-system-experiment/Base.h new file mode 100644 index 0000000..b3ac1ee --- /dev/null +++ b/works/life/operating-system-experiment/Base.h @@ -0,0 +1,22 @@ +#ifndef HEADER_BASE_H +#define HEADER_BASE_H + +#ifdef _WIN32 +#define CRU_WINDOWS 1 +#endif + +#ifdef CRU_WINDOWS +#include +#endif + +#ifdef CRU_WINDOWS +#ifdef CRU_EXPORT_API +#define CRU_API __declspec(dllexport) +#else +#define CRU_API __declspec(dllimport) +#endif +#else +#define CRU_API +#endif + +#endif \ No newline at end of file diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt new file mode 100644 index 0000000..2c46b0f --- /dev/null +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.20) + +set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake + CACHE STRING "Vcpkg toolchain file") + +project(operating-system-experiment) + +set(CMAKE_CXX_STANDARD 17) + +find_package(fmt CONFIG REQUIRED) +find_package(Microsoft.GSL CONFIG REQUIRED) +add_library(cru_system SHARED Thread.cpp) +target_link_libraries(cru_system PUBLIC Microsoft.GSL::GSL fmt::fmt) +target_compile_definitions(cru_system PUBLIC CRU_EXPORT_API) + +add_executable(main main.cpp) +target_link_libraries(main PRIVATE cru_system) \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp new file mode 100644 index 0000000..b91ca69 --- /dev/null +++ b/works/life/operating-system-experiment/Thread.cpp @@ -0,0 +1,67 @@ +#include "Thread.h" + +#include +#include +#include + +namespace cru { +Thread::Thread(Thread &&other) noexcept + : joined_(other.joined_), thread_handle_(other.thread_handle_) { + other.joined_ = false; + other.thread_handle_ = nullptr; +} + +Thread &Thread::operator=(Thread &&other) noexcept { + if (this != &other) { + joined_ = other.joined_; + thread_handle_ = other.thread_handle_; + other.joined_ = false; + other.thread_handle_ = nullptr; + } + + return *this; +} + +Thread::~Thread() { Destroy(); } + +void Thread::Join() { + assert(thread_handle_); + joined_ = true; + WaitForSingleObject(thread_handle_, INFINITE); +} + +void Thread::Detach() { + assert(thread_handle_); + detached_ = true; +} + +void Thread::swap(Thread &other) noexcept { +#ifdef CRU_WINDOWS + Thread temp = std::move(*this); + *this = std::move(other); + other = std::move(temp); +#else +#endif +} + +void Thread::Destroy() noexcept { + if (!detached_ && !joined_ && thread_handle_ != nullptr) { + std::terminate(); + } else { + joined_ = false; + thread_handle_ = nullptr; + } +} + +namespace details { +#ifdef CRU_WINDOWS +DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) { + auto p = static_cast *>(lpParameter); + (*p)(); + delete p; + return 0; +} +#else +#endif +} // namespace details +} // namespace cru \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h new file mode 100644 index 0000000..c71c11f --- /dev/null +++ b/works/life/operating-system-experiment/Thread.h @@ -0,0 +1,68 @@ +#ifndef HEADER_THREAD_H +#define HEADER_THREAD_H + +#include "Base.h" + +#ifdef __cplusplus + +#include +#include +#include +#include +#include + +namespace cru { +class CRU_API Thread { +public: + Thread() = default; + template Thread(Fn &&process, Args &&...args); + Thread(const Thread &other) = delete; + Thread(Thread &&other) noexcept; + Thread &operator=(const Thread &other) = delete; + Thread &operator=(Thread &&other) noexcept; + ~Thread(); + +public: + void Join(); + void Detach(); + + void swap(Thread &other) noexcept; + +private: + void Destroy() noexcept; + +private: + bool detached_ = false; + bool joined_ = false; + +#ifdef CRU_WINDOWS + DWORD thread_id_ = 0; + HANDLE thread_handle_ = nullptr; +#endif +}; + +namespace details { +#ifdef CRU_WINDOWS +CRU_API DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter); +#else +#endif +} // namespace details + +template +Thread::Thread(Fn &&process, Args &&...args) { + std::tuple...> a{std::forward(args)...}; + auto p = new std::function( + [process = std::forward(process), args = std::move(a)]() { + std::apply(process, std::move(args)); + }); + +#ifdef CRU_WINDOWS + thread_handle_ = ::CreateThread(nullptr, 0, &::cru::details::ThreadProc, + static_cast(p), 0, &thread_id_); +#endif +}; +} // namespace cru + +#endif + +#endif diff --git a/works/life/operating-system-experiment/main.cpp b/works/life/operating-system-experiment/main.cpp new file mode 100644 index 0000000..ada8c85 --- /dev/null +++ b/works/life/operating-system-experiment/main.cpp @@ -0,0 +1,16 @@ +#include "Thread.h" + +#include +#include + +int main() { + cru::Thread thread1([](const std::string &s) { std::cout << s; }, + "Hello world! 1\n"); + thread1.Join(); + + cru::Thread thread2([](const std::string &s) { std::cout << s; }, + "Hello world! 2\n"); + thread2.Join(); + + return 0; +} -- cgit v1.2.3 From 8bdb5db67fa3eeda755511f91fd257bde548a18f Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 9 Jun 2021 22:28:01 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Base.h | 4 -- .../operating-system-experiment/CMakeLists.txt | 4 ++ works/life/operating-system-experiment/Thread.cpp | 53 ++++++++++++++++++++-- works/life/operating-system-experiment/Thread.h | 17 +++++++ 4 files changed, 69 insertions(+), 9 deletions(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/Base.h b/works/life/operating-system-experiment/Base.h index b3ac1ee..6964c1c 100644 --- a/works/life/operating-system-experiment/Base.h +++ b/works/life/operating-system-experiment/Base.h @@ -5,10 +5,6 @@ #define CRU_WINDOWS 1 #endif -#ifdef CRU_WINDOWS -#include -#endif - #ifdef CRU_WINDOWS #ifdef CRU_EXPORT_API #define CRU_API __declspec(dllexport) diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 2c46b0f..540574b 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -12,6 +12,10 @@ find_package(Microsoft.GSL CONFIG REQUIRED) add_library(cru_system SHARED Thread.cpp) target_link_libraries(cru_system PUBLIC Microsoft.GSL::GSL fmt::fmt) target_compile_definitions(cru_system PUBLIC CRU_EXPORT_API) +if(UNIX) +target_link_libraries(cru_system PUBLIC pthread) +endif() + add_executable(main main.cpp) target_link_libraries(main PRIVATE cru_system) \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index b91ca69..8230c1c 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -2,21 +2,36 @@ #include #include +#include #include namespace cru { Thread::Thread(Thread &&other) noexcept - : joined_(other.joined_), thread_handle_(other.thread_handle_) { + : detached_(other.detached_), joined_(other.joined_), +#ifdef CRU_WINDOWS + thread_handle_(other.thread_handle_) +#else + thread_(std::move(other.thread_)) +#endif +{ other.joined_ = false; +#ifdef CRU_WINDOWS other.thread_handle_ = nullptr; -} +#endif +} // namespace cru Thread &Thread::operator=(Thread &&other) noexcept { if (this != &other) { + detached_ = other.detached_; joined_ = other.joined_; +#ifdef CRU_WINDOWS thread_handle_ = other.thread_handle_; - other.joined_ = false; other.thread_handle_ = nullptr; +#else + thread_ = std::move(other.thread_); +#endif + other.detached_ = false; + other.joined_ = false; } return *this; @@ -25,13 +40,23 @@ Thread &Thread::operator=(Thread &&other) noexcept { Thread::~Thread() { Destroy(); } void Thread::Join() { - assert(thread_handle_); joined_ = true; +#ifdef CRU_WINDOWS + assert(thread_handle_); WaitForSingleObject(thread_handle_, INFINITE); +#else + assert(thread_); + auto c = pthread_join(*thread_, nullptr); + assert(c == 0); +#endif } void Thread::Detach() { +#ifdef CRU_WINDOWS assert(thread_handle_); +#else + assert(thread_); +#endif detached_ = true; } @@ -45,11 +70,22 @@ void Thread::swap(Thread &other) noexcept { } void Thread::Destroy() noexcept { - if (!detached_ && !joined_ && thread_handle_ != nullptr) { + if (!detached_ && !joined_ && +#ifdef CRU_WINDOWS + thread_handle_ != nullptr +#else + thread_ != nullptr +#endif + ) { std::terminate(); } else { + detached_ = false; joined_ = false; +#ifdef CRU_WINDOWS thread_handle_ = nullptr; +#else + thread_ = nullptr; +#endif } } @@ -62,6 +98,13 @@ DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) { return 0; } #else +void *ThreadProc(void *data) { + auto p = static_cast *>(data); + (*p)(); + delete p; + return nullptr; +} + #endif } // namespace details } // namespace cru \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h index c71c11f..79c1728 100644 --- a/works/life/operating-system-experiment/Thread.h +++ b/works/life/operating-system-experiment/Thread.h @@ -3,9 +3,17 @@ #include "Base.h" +#ifdef CRU_WINDOWS +#include +#else +#include +#endif + #ifdef __cplusplus +#include #include +#include #include #include #include @@ -38,6 +46,8 @@ private: #ifdef CRU_WINDOWS DWORD thread_id_ = 0; HANDLE thread_handle_ = nullptr; +#else + std::unique_ptr thread_; #endif }; @@ -45,6 +55,7 @@ namespace details { #ifdef CRU_WINDOWS CRU_API DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter); #else +void *ThreadProc(void *data); #endif } // namespace details @@ -59,6 +70,12 @@ Thread::Thread(Fn &&process, Args &&...args) { #ifdef CRU_WINDOWS thread_handle_ = ::CreateThread(nullptr, 0, &::cru::details::ThreadProc, static_cast(p), 0, &thread_id_); + assert(thread_handle_); +#else + thread_.reset(new pthread_t()); + auto c = pthread_create(thread_.get(), nullptr, details::ThreadProc, + static_cast(p)); + assert(c == 0); #endif }; } // namespace cru -- cgit v1.2.3 From 8268724a054a42f9446736c42d8f04a0207aa12d Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 9 Jun 2021 22:30:14 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Thread.h | 1 + 1 file changed, 1 insertion(+) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h index c71c11f..cdeecac 100644 --- a/works/life/operating-system-experiment/Thread.h +++ b/works/life/operating-system-experiment/Thread.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace cru { class CRU_API Thread { -- cgit v1.2.3 From 93d8feccd79b35fc890fc8629d6da2c2baa57762 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 9 Jun 2021 22:32:01 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Thread.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index 8230c1c..9d9f5dd 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -2,7 +2,6 @@ #include #include -#include #include namespace cru { -- cgit v1.2.3 From ef593ba2d445af515214d63bfd3942be9d673467 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:12:25 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 8 ++- .../operating-system-experiment/DataRaceDemo.cpp | 27 ++++++++ works/life/operating-system-experiment/Mutex.cpp | 78 ++++++++++++++++++++++ works/life/operating-system-experiment/Mutex.h | 44 ++++++++++++ works/life/operating-system-experiment/Thread.cpp | 31 +++++++++ works/life/operating-system-experiment/Thread.h | 15 ++++- 6 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 works/life/operating-system-experiment/DataRaceDemo.cpp create mode 100644 works/life/operating-system-experiment/Mutex.cpp create mode 100644 works/life/operating-system-experiment/Mutex.h (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 540574b..806ec74 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -9,13 +9,15 @@ set(CMAKE_CXX_STANDARD 17) find_package(fmt CONFIG REQUIRED) find_package(Microsoft.GSL CONFIG REQUIRED) -add_library(cru_system SHARED Thread.cpp) +add_library(cru_system SHARED Thread.cpp Mutex.cpp) target_link_libraries(cru_system PUBLIC Microsoft.GSL::GSL fmt::fmt) target_compile_definitions(cru_system PUBLIC CRU_EXPORT_API) if(UNIX) target_link_libraries(cru_system PUBLIC pthread) endif() - add_executable(main main.cpp) -target_link_libraries(main PRIVATE cru_system) \ No newline at end of file +target_link_libraries(main PRIVATE cru_system) + +add_executable(data_race_demo DataRaceDemo.cpp) +target_link_libraries(data_race_demo PRIVATE cru_system) diff --git a/works/life/operating-system-experiment/DataRaceDemo.cpp b/works/life/operating-system-experiment/DataRaceDemo.cpp new file mode 100644 index 0000000..9589eb3 --- /dev/null +++ b/works/life/operating-system-experiment/DataRaceDemo.cpp @@ -0,0 +1,27 @@ +#include "Thread.h" + +#include + +int main() { + unsigned data = 0; + + cru::Thread t1([&data] { + for (int i = 0; i < 100000; i++) + data += 10; + }); + + cru::Thread t2([&data] { + for (int i = 0; i < 100000; i++) + data += 10; + }); + + 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 == 200000 ? "correct" : "false") << '\n'; + + return 0; +} 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 diff --git a/works/life/operating-system-experiment/Mutex.h b/works/life/operating-system-experiment/Mutex.h new file mode 100644 index 0000000..163d9ca --- /dev/null +++ b/works/life/operating-system-experiment/Mutex.h @@ -0,0 +1,44 @@ +#ifndef HEADER_MUTEX_H +#define HEADER_MUTEX_H + +#include "Base.h" + +#include + +#ifdef CRU_WINDOWS +#include +#else +#include +#endif + +namespace cru { +class CRU_API Mutex { +public: + Mutex(); + + Mutex(const Mutex &other) = delete; + Mutex &operator=(const Mutex &other) = delete; + + Mutex(Mutex &&other); + Mutex &operator=(Mutex &&other); + + ~Mutex(); + +public: + void Lock(); + bool TryLock(); + + void Unlock(); + +private: + void Destroy(); + +private: +#ifdef CRU_WINDOWS +#else + std::unique_ptr mutex_; +#endif +}; +} // namespace cru + +#endif \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index 9d9f5dd..7e3c784 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -59,6 +59,36 @@ void Thread::Detach() { detached_ = true; } +#ifdef CRU_WINDOWS +DWORD +#else +pthread_t +#endif +Thread::GetNativeID() { +#ifdef CRU_WINDOWS + assert(thread_handle_); + return thread_id_; +#else + assert(thread_); + return *thread_; +#endif +} + +#ifdef CRU_WINDOWS +HANDLE +#else +pthread_t +#endif +Thread::GetNativeHandle() { +#ifdef CRU_WINDOWS + assert(thread_handle_); + return thread_handle_; +#else + assert(thread_); + return *thread_; +#endif +} + void Thread::swap(Thread &other) noexcept { #ifdef CRU_WINDOWS Thread temp = std::move(*this); @@ -81,6 +111,7 @@ void Thread::Destroy() noexcept { detached_ = false; joined_ = false; #ifdef CRU_WINDOWS + thread_id_ = 0; thread_handle_ = nullptr; #else thread_ = nullptr; diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h index 69a402c..56fdcb0 100644 --- a/works/life/operating-system-experiment/Thread.h +++ b/works/life/operating-system-experiment/Thread.h @@ -18,7 +18,6 @@ #include #include #include -#include namespace cru { class CRU_API Thread { @@ -35,6 +34,20 @@ public: void Join(); void Detach(); +#ifdef CRU_WINDOWS + DWORD +#else + pthread_t +#endif + GetNativeID(); + +#ifdef CRU_WINDOWS + HANDLE +#else + pthread_t +#endif + GetNativeHandle(); + void swap(Thread &other) noexcept; private: -- 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') 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') 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 91ec864a9c8e023f9f87d1c079a1cd8024844a7a Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:43:23 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/CMakeLists.txt | 2 +- works/life/operating-system-experiment/Interlocked.cpp | 16 ++++++++++++++++ works/life/operating-system-experiment/Interlocked.hpp | 10 ++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 works/life/operating-system-experiment/Interlocked.cpp create mode 100644 works/life/operating-system-experiment/Interlocked.hpp (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 139d2ba..bd50319 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) +add_library(cru_system SHARED Thread.cpp Mutex.cpp Interlocked.cpp) target_link_libraries(cru_system PUBLIC Microsoft.GSL::GSL fmt::fmt) target_compile_definitions(cru_system PUBLIC CRU_EXPORT_API) if(UNIX) diff --git a/works/life/operating-system-experiment/Interlocked.cpp b/works/life/operating-system-experiment/Interlocked.cpp new file mode 100644 index 0000000..4f224e4 --- /dev/null +++ b/works/life/operating-system-experiment/Interlocked.cpp @@ -0,0 +1,16 @@ +#include "Interlocked.hpp" + +#ifdef CRU_WINDOWS +#include +#else +#endif + +namespace cru { +void InterlockedIncrease(volatile long long *v) { +#ifdef CRU_WINDOWS + InterlockedIncrement64(v); +#else + +#endif +} +} // namespace cru diff --git a/works/life/operating-system-experiment/Interlocked.hpp b/works/life/operating-system-experiment/Interlocked.hpp new file mode 100644 index 0000000..1151e39 --- /dev/null +++ b/works/life/operating-system-experiment/Interlocked.hpp @@ -0,0 +1,10 @@ +#ifndef HRADER_INTERLOCKED_H +#define HRADER_INTERLOCKED_H + +#include "Base.h" + +namespace cru { +CRU_API void InterlockedIncrease(volatile long long *v); +} + +#endif -- cgit v1.2.3 From 1ce9ffb961fa2d2f878131bfc6fe38ce9317a401 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:47:14 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Interlocked.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/Interlocked.cpp b/works/life/operating-system-experiment/Interlocked.cpp index 4f224e4..1c0f638 100644 --- a/works/life/operating-system-experiment/Interlocked.cpp +++ b/works/life/operating-system-experiment/Interlocked.cpp @@ -6,11 +6,11 @@ #endif namespace cru { -void InterlockedIncrease(volatile long long *v) { +void InterlockedAdd(volatile long long *v, long long a) { #ifdef CRU_WINDOWS - InterlockedIncrement64(v); + InterlockedAdd64(v, a); #else - + __sync_fetch_and_add(v, a); #endif } } // namespace cru -- cgit v1.2.3 From 06c91dd3a3d17bd1f884c7e322fd7701a95ce7a9 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:48:45 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/Interlocked.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/Interlocked.hpp b/works/life/operating-system-experiment/Interlocked.hpp index 1151e39..aa5dbfc 100644 --- a/works/life/operating-system-experiment/Interlocked.hpp +++ b/works/life/operating-system-experiment/Interlocked.hpp @@ -4,7 +4,7 @@ #include "Base.h" namespace cru { -CRU_API void InterlockedIncrease(volatile long long *v); +CRU_API void InterlockedAdd(volatile long long *v, long long a); } #endif -- cgit v1.2.3 From 5018c2b40009258ed0691cbbb1dcc4d8ac4a809b Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 10 Jun 2021 11:55:27 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 3 +++ .../operating-system-experiment/Interlocked.cpp | 2 +- .../operating-system-experiment/Interlocked.hpp | 2 +- .../InterlockedAvoidDataRaceDemo.cpp | 28 ++++++++++++++++++++++ works/life/operating-system-experiment/Thread.cpp | 18 ++++++++++++-- works/life/operating-system-experiment/Thread.h | 12 ++-------- 6 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 works/life/operating-system-experiment/InterlockedAvoidDataRaceDemo.cpp (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index bd50319..8b4617f 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -24,3 +24,6 @@ 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) + +add_executable(interlocked_avoid_data_race_demo InterlockedAvoidDataRaceDemo.cpp) +target_link_libraries(interlocked_avoid_data_race_demo PRIVATE cru_system) diff --git a/works/life/operating-system-experiment/Interlocked.cpp b/works/life/operating-system-experiment/Interlocked.cpp index 1c0f638..7fc8c6b 100644 --- a/works/life/operating-system-experiment/Interlocked.cpp +++ b/works/life/operating-system-experiment/Interlocked.cpp @@ -6,7 +6,7 @@ #endif namespace cru { -void InterlockedAdd(volatile long long *v, long long a) { +void CruInterlockedAdd(volatile long long *v, long long a) { #ifdef CRU_WINDOWS InterlockedAdd64(v, a); #else diff --git a/works/life/operating-system-experiment/Interlocked.hpp b/works/life/operating-system-experiment/Interlocked.hpp index aa5dbfc..7e09b60 100644 --- a/works/life/operating-system-experiment/Interlocked.hpp +++ b/works/life/operating-system-experiment/Interlocked.hpp @@ -4,7 +4,7 @@ #include "Base.h" namespace cru { -CRU_API void InterlockedAdd(volatile long long *v, long long a); +CRU_API void CruInterlockedAdd(volatile long long *v, long long a); } #endif diff --git a/works/life/operating-system-experiment/InterlockedAvoidDataRaceDemo.cpp b/works/life/operating-system-experiment/InterlockedAvoidDataRaceDemo.cpp new file mode 100644 index 0000000..91d6d50 --- /dev/null +++ b/works/life/operating-system-experiment/InterlockedAvoidDataRaceDemo.cpp @@ -0,0 +1,28 @@ +#include "Interlocked.hpp" +#include "Thread.h" + +#include + +int main() { + volatile long long data = 0; + + cru::Thread t1([&data] { + for (int i = 0; i < 100000; i++) + cru::CruInterlockedAdd(&data, 10); + }); + + cru::Thread t2([&data] { + for (int i = 0; i < 100000; i++) + cru::CruInterlockedAdd(&data, 10); + }); + + 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; +} diff --git a/works/life/operating-system-experiment/Thread.cpp b/works/life/operating-system-experiment/Thread.cpp index a5f526d..657c69f 100644 --- a/works/life/operating-system-experiment/Thread.cpp +++ b/works/life/operating-system-experiment/Thread.cpp @@ -122,7 +122,7 @@ void Thread::Destroy() noexcept { } } -namespace details { +namespace { #ifdef CRU_WINDOWS DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) { auto p = static_cast *>(lpParameter); @@ -139,5 +139,19 @@ void *ThreadProc(void *data) { } #endif -} // namespace details +} // namespace + +void Thread::CreateThread(std::function *proc) { +#ifdef CRU_WINDOWS + thread_handle_ = ::CreateThread(nullptr, 0, ThreadProc, + static_cast(proc), 0, &thread_id_); + assert(thread_handle_); +#else + thread_.reset(new pthread_t()); + auto c = pthread_create(thread_.get(), nullptr, ThreadProc, + static_cast(proc)); + assert(c == 0); +#endif +}; + } // namespace cru \ No newline at end of file diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h index 56fdcb0..735407c 100644 --- a/works/life/operating-system-experiment/Thread.h +++ b/works/life/operating-system-experiment/Thread.h @@ -52,6 +52,7 @@ public: private: void Destroy() noexcept; + void CreateThread(std::function *proc); private: bool detached_ = false; @@ -81,16 +82,7 @@ Thread::Thread(Fn &&process, Args &&...args) { std::apply(process, std::move(args)); }); -#ifdef CRU_WINDOWS - thread_handle_ = ::CreateThread(nullptr, 0, &::cru::details::ThreadProc, - static_cast(p), 0, &thread_id_); - assert(thread_handle_); -#else - thread_.reset(new pthread_t()); - auto c = pthread_create(thread_.get(), nullptr, details::ThreadProc, - static_cast(p)); - assert(c == 0); -#endif + CreateThread(p); }; } // namespace cru -- cgit v1.2.3 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 (limited to 'works/life/operating-system-experiment') 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 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') 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 From e9cfa972d7ffd09584b678b42cb60bf50b8efa92 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 11 Jun 2021 11:24:08 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 2 + .../ParallelCalculationDemo.cpp | 73 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 works/life/operating-system-experiment/ParallelCalculationDemo.cpp (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index c8afc24..5671b4a 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -31,3 +31,5 @@ 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) +add_executable(parallel_calculation_demo ParallelCalculationDemo.cpp) +target_link_libraries(parallel_calculation_demo PRIVATE cru_system) diff --git a/works/life/operating-system-experiment/ParallelCalculationDemo.cpp b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp new file mode 100644 index 0000000..31ff2bf --- /dev/null +++ b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp @@ -0,0 +1,73 @@ +#include "Thread.h" + +#include + +const long long N = 1e9; + +int main(int argc, char **argv) { + int thread_number; + if (argc == 1) { + thread_number = 1; + } else if (argc == 2) { + thread_number = std::atoi(argv[1]); + if (thread_number <= 0) { + std::cerr << "Argument must be a positive integer.\n"; + } + } else { + std::cerr << "Too many arguments.\n"; + } + + std::cout << "Use " << thread_number << " threads to calculate sum of 1-" << N + << ".\n"; + + if (thread_number == 1) { + long long sum = 0; + for (long long i = 1; i <= 1e9; i++) { + sum += i; + } + std::cout << "Sum of 1-" << N << " is " << sum << '\n'; + } else { + std::vector threads(thread_number); + std::vector partial_sum(thread_number); + + long long step = N / thread_number; + + for (int i = 0; i < thread_number; i++) { + long long start = step * i; + long long end = step * (i + 1); + + long long &ps = partial_sum[i]; + + if (i == thread_number - 1) { + threads[i] = cru::Thread([&ps, start] { + long long sum = 0; + for (long long j = start; j <= 1e9; j++) { + sum += j; + } + ps = sum; + }); + } else { + threads[i] = cru::Thread([&ps, start, end] { + long long sum = 0; + for (int j = start; j < end; j++) { + sum += j; + } + ps = sum; + }); + } + } + + for (auto &thread : threads) { + thread.Join(); + } + + long long sum = 0; + for (auto ps : partial_sum) { + sum += ps; + } + + std::cout << "Sum of 1-" << N << " is " << sum << '\n'; + } + + return 0; +} -- cgit v1.2.3 From 2c7ceca3e58543c36098fd46de711d9cd80a4d12 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 11 Jun 2021 11:34:16 +0800 Subject: import(life): ... --- works/life/operating-system-experiment/ParallelCalculationDemo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/ParallelCalculationDemo.cpp b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp index 31ff2bf..7340da8 100644 --- a/works/life/operating-system-experiment/ParallelCalculationDemo.cpp +++ b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp @@ -41,7 +41,7 @@ int main(int argc, char **argv) { if (i == thread_number - 1) { threads[i] = cru::Thread([&ps, start] { long long sum = 0; - for (long long j = start; j <= 1e9; j++) { + for (long long j = start; j <= N; j++) { sum += j; } ps = sum; -- cgit v1.2.3 From dc0dfeec23158268268da5a16364abb1f0de5a06 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 12 Jun 2021 23:20:15 +0800 Subject: import(life): ... --- .../operating-system-experiment/CMakeLists.txt | 2 ++ .../DeadLockDetectionDemo.cpp | 25 ++++++++++++++++++++++ .../ParallelCalculationDemo.cpp | 2 ++ works/life/operating-system-experiment/Thread.h | 8 ------- 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 works/life/operating-system-experiment/DeadLockDetectionDemo.cpp (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/CMakeLists.txt b/works/life/operating-system-experiment/CMakeLists.txt index 5671b4a..79fe786 100644 --- a/works/life/operating-system-experiment/CMakeLists.txt +++ b/works/life/operating-system-experiment/CMakeLists.txt @@ -33,3 +33,5 @@ target_link_libraries(semaphore_avoid_data_race_demo PRIVATE cru_system) add_executable(parallel_calculation_demo ParallelCalculationDemo.cpp) target_link_libraries(parallel_calculation_demo PRIVATE cru_system) + +add_executable(dead_lock_detection_demo DeadLockDetectionDemo.cpp) diff --git a/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp new file mode 100644 index 0000000..b22549e --- /dev/null +++ b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int main() { + std::vector ns; + + while (!std::cin.eof() || std::cin) { + int n; + std::cin >> n; + ns.push_back(n); + } + + if (!std::cin.eof()) { + std::cerr << "Failed to parse input.\n"; + return -1; + } + + if (ns.size() % 2 != 0) { + std::cerr << "Input integer number must be even.\n"; + return -1; + } + + +} diff --git a/works/life/operating-system-experiment/ParallelCalculationDemo.cpp b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp index 7340da8..0174c55 100644 --- a/works/life/operating-system-experiment/ParallelCalculationDemo.cpp +++ b/works/life/operating-system-experiment/ParallelCalculationDemo.cpp @@ -12,9 +12,11 @@ int main(int argc, char **argv) { thread_number = std::atoi(argv[1]); if (thread_number <= 0) { std::cerr << "Argument must be a positive integer.\n"; + return -1; } } else { std::cerr << "Too many arguments.\n"; + return -1; } std::cout << "Use " << thread_number << " threads to calculate sum of 1-" << N diff --git a/works/life/operating-system-experiment/Thread.h b/works/life/operating-system-experiment/Thread.h index 735407c..4ad1ef4 100644 --- a/works/life/operating-system-experiment/Thread.h +++ b/works/life/operating-system-experiment/Thread.h @@ -66,14 +66,6 @@ private: #endif }; -namespace details { -#ifdef CRU_WINDOWS -CRU_API DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter); -#else -void *ThreadProc(void *data); -#endif -} // namespace details - template Thread::Thread(Fn &&process, Args &&...args) { std::tuple...> a{std::forward(args)...}; -- cgit v1.2.3 From 60fb578a0202d354b2fdc5cdf86c04fb9d62c729 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 14 Jun 2021 18:38:04 +0800 Subject: import(life): ... --- .../DeadLockDetectionDemo.cpp | 89 +++++++++++++++++++++- .../DeadLockTestData1.txt | 4 + .../DeadLockTestData2.txt | 4 + .../DeadLockTestData3.txt | 6 ++ .../DeadLockTestData4.txt | 9 +++ 5 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 works/life/operating-system-experiment/DeadLockTestData1.txt create mode 100644 works/life/operating-system-experiment/DeadLockTestData2.txt create mode 100644 works/life/operating-system-experiment/DeadLockTestData3.txt create mode 100644 works/life/operating-system-experiment/DeadLockTestData4.txt (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp index b22549e..e043161 100644 --- a/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp +++ b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp @@ -1,14 +1,66 @@ -#include #include +#include +#include #include +const int LOCK_START_INDEX = 10000; + +struct Node { + int id; +}; + +bool operator==(const Node &left, const Node &right) { + return left.id == right.id; +} + +template <> struct std::hash { + std::size_t operator()(const Node &node) const { + return std::hash{}(node.id); + } +}; + +std::ostream &operator<<(std::ostream &left, const Node &right) { + left << (right.id > LOCK_START_INDEX ? "lock" : "process") << ' ' + << (right.id > LOCK_START_INDEX ? right.id - LOCK_START_INDEX + : right.id); + return left; +} + +bool dfs( + const Node *root, + std::unordered_map> &edges, + std::unordered_map &visited) { + + if (visited[root]) { + std::cout << "Ohhhhhh, it is already visited!\n"; + return true; + } + + visited[root] = true; + auto r = edges.find(root); + if (r != edges.cend()) + for (auto n : r->second) { + std::cout << "from " << *root << " go to " << *n << "\n"; + if (dfs(n, edges, visited)) + return true; + std::cout << "from " << *n << " back to " << *root << "\n"; + } + + edges.erase(root); + return false; +} + +// 1 10001 -> process 1 is waiting for lock 10001 +// 10001 1 -> lock 10001 is owned by process 1 + int main() { std::vector ns; - while (!std::cin.eof() || std::cin) { + while (std::cin) { int n; std::cin >> n; - ns.push_back(n); + if (std::cin) + ns.push_back(n); } if (!std::cin.eof()) { @@ -21,5 +73,34 @@ int main() { return -1; } - + std::unordered_set nodes; + std::unordered_map> edges; + + for (int i = 0; i < ns.size(); i += 2) { + int p = ns[i]; + int l = ns[i + 1]; + auto r1 = nodes.insert({p}); + auto r2 = nodes.insert({l}); + edges[&(*r1.first)].insert(&(*r2.first)); + } + + bool h = false; + + while (!edges.empty()) { + auto n = edges.cbegin()->first; + std::unordered_map visited; + std::cout << "Begin to detect child graph containing '" << *n << "'.\n"; + if (dfs(n, edges, visited)) { + h = true; + break; + } + } + + if (h) { + std::cout << "Cycle, aka dead lock, detected.\n"; + } else { + std::cout << "You are free of dead lock!!!\n"; + } + + return 0; } diff --git a/works/life/operating-system-experiment/DeadLockTestData1.txt b/works/life/operating-system-experiment/DeadLockTestData1.txt new file mode 100644 index 0000000..0c8dd14 --- /dev/null +++ b/works/life/operating-system-experiment/DeadLockTestData1.txt @@ -0,0 +1,4 @@ +1 10001 +2 10001 +3 10001 +4 10001 diff --git a/works/life/operating-system-experiment/DeadLockTestData2.txt b/works/life/operating-system-experiment/DeadLockTestData2.txt new file mode 100644 index 0000000..d632f2a --- /dev/null +++ b/works/life/operating-system-experiment/DeadLockTestData2.txt @@ -0,0 +1,4 @@ +10001 1 +1 10002 +2 10001 +10002 2 diff --git a/works/life/operating-system-experiment/DeadLockTestData3.txt b/works/life/operating-system-experiment/DeadLockTestData3.txt new file mode 100644 index 0000000..1e1692d --- /dev/null +++ b/works/life/operating-system-experiment/DeadLockTestData3.txt @@ -0,0 +1,6 @@ +1 10001 +10001 2 +2 10002 +10002 3 +3 10003 +10003 1 diff --git a/works/life/operating-system-experiment/DeadLockTestData4.txt b/works/life/operating-system-experiment/DeadLockTestData4.txt new file mode 100644 index 0000000..d124102 --- /dev/null +++ b/works/life/operating-system-experiment/DeadLockTestData4.txt @@ -0,0 +1,9 @@ +1 10001 +2 10001 +3 10002 +3 10004 +10001 3 +4 10001 +4 10005 +10004 5 +10005 5 -- cgit v1.2.3 From 213363383b5864d236cfce711920f76a2450de07 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 16 Jun 2021 20:18:19 +0800 Subject: import(life): ... --- .../operating-system-experiment/DeadLockDetectionDemo.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'works/life/operating-system-experiment') diff --git a/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp index e043161..bea2b43 100644 --- a/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp +++ b/works/life/operating-system-experiment/DeadLockDetectionDemo.cpp @@ -1,3 +1,13 @@ +// Demo使用方法: +// 本程序采用标准C++11代码写成,请使用支持C++11的编译器编译。 +// +// 程序接受的输入为n个整数对,其中1-10000表示进程,10001及以上表示锁,顺序很重要: +// 1 10001 -> process 1 is acquiring or waiting for lock 1 +// 10001 1 -> lock 1 is owned by process 1 +// +// 建议采用重定向输入至文件的方式输入,提供4个典型情况的测试数据。 +// + #include #include #include @@ -50,9 +60,6 @@ bool dfs( return false; } -// 1 10001 -> process 1 is waiting for lock 10001 -// 10001 1 -> lock 10001 is owned by process 1 - int main() { std::vector ns; -- cgit v1.2.3