2023 Homework3 === tags: contributed by < `25077667` > # 挑戰 3 ## 前情提要 眾所周知,讀寫鎖是實踐讀多寫少情境的優化方式之一。相關討論會也在 bilibili 認定是比較困難的問題。 並且根據我的經驗,Windows XP 不支援 C++17 的 std::shared_mutex ,這問題曾經讓我踩坑 [Tips 紀錄](https://hackmd.io/@25077667/HyvJ4j6vi)。 (記得以前我有看過一篇繁體中文的文章,印象中 theme 是綠色的,在介紹 C\+\+17 對 rwlock 支援後,優雅的程式設計風格,但一時間找不到,歡迎補充) 當時 use-case 是: 要開發跨平台的程式,並且要兼容 Windows XP and Windows server 2003。 但很不幸的,在我開發的功能上,會需要有 multiple producer 跟 multiple consumer 的架構 於是當時採用 std::shared_mutex (17) 搭配 std::shared_lock (14) 與 std::unique_lock (11) 而在 CI 上發現: **所有平台都執行成功,唯獨 Windows XP / 2003 壞掉** 錯誤訊息顯示: > "AcquireSRWlockExclusive" not found in KERNEL32.dll 類似[圖例](https://sourceforge.net/p/dvdstyler/discussion/318795/thread/bb72a35f36/): ![](https://hackmd.io/_uploads/S1gZlj_a3.png) 這問題主要是因為在 MSVC 當中,選擇 Windows SDK 7.0 (v140_xp) 即使是 static linking 在需要 Windows kernel32.dll 的支援時,也只能依賴於執行時期的 kernel32.dll 與 ntdll.dll 因此,當我們使用 Visual Studio 選擇到 `/std:c++17`, `/std:c++20` 甚至 `/std:c++latest` 時 即便 syntactically legal, linking legal ,但, run time not found。 > 該資訊可以於 Windows [MSDN](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive) 上看到 :::spoiler 於 Linux 中類似問題如 ``` /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found ``` ::: murmur: > 身為 Linux, C++ 開發者,在 Windows 上面踩了一堆坑,我認為應該對待 MSVC C++ 是類似 C++ 程式語言。 > 除了 coding style 不同,他也總會在你不預期的地方有「**不一致的行為**」(意即它不遵守 C++ 標準) > 最近又因為需要開發其他功能,可能需要使用到 rwlock,於是我決定先投入這問題的研究 ## 常見的實作 ### 有 POSIX ```c pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; ``` ```cpp void lock_shared() { while (true) { int ret = pthread_rwlock_rdlock(&rwlock); switch (ret) { case 0: return; // Lock acquired successfully case EAGAIN: continue; // Retrying is acceptable based on forward progress guarantees case EDEADLK: throw std::system_error(std::make_error_code(std::errc::resource_deadlock_would_occur)); default: assert(false); // Handle other error cases, like EINVAL } } } ``` 詳參考資料: https://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_rwlock_init.html https://linux.die.net/man/3/pthread_rwlock_rdlock https://codebrowser.dev/glibc/glibc/nptl/pthread_rwlock_common.c.html#281 ### 沒有 POSIX 這邊就要自己實作 counter 了。 這邊本質的想法是:有人在讀,那就 + 1,你要讀一起 + 1,讀完放掉 - 1 如果你要寫,那就等到 counter 變成 0 才能進入 cs 如同作業區介紹的 ## Pull request https://github.com/sysprog21/concurrent-programs/pull/19