# 作業系統概論作業二 ###### tags: `OS` - 0716023 ## Question There are some potential issues with theprograms. Please identify at least two issues and describe the corresponding solutionsthat would fix the issues. ## Answer ### Problem I - 執行緒安全問題 這個程式並沒有保證執行緒安全。亦即,當多個 client 同時在修改值時,並不保證最後在共享記憶體中的值是其中一個 client 所寫的值。比如說 client A 和 B 同時寫入值為 $a$ 和 $b$ ,有可能最後的值非 $a$ 也非 $b$ 而是 $c$ 。 要改善這個問題,最直覺的解法是透過鎖來保證執行緒安全。然而不同的 client 是為不同的 process ,很難透過共用互斥鎖來達成執行緒安全。 最根本的原因出在這是 server/client 程式。一般在實作這樣的程式時,並不是透過共享記憶體,而是透過 I/O 和多執行緒來達成。 我們可以將程式改造如下: server 開一個 port 或其他方式,使得各 client 能夠與 server 有專有的聯絡通道。當 client 想改值時,將此值傳給 server 令 server 去改;當 client 想讀值時,傳 request 給 server 令其 response 該值。最後,在 server 端使用互斥鎖或讀寫鎖,就可以保證讀寫值時的執行緒安全。 ### Problem II - 共享記憶體生命週期問題之一 理想的情況是,只有當 server 正在運行時, client 才能正常運行;當 server 結束時, client 不應該能夠寫值或讀值。然而,使用 `shmctl` 和 `SHM_RMID` 來釋放共享記憶體空間時,唯有在最後一個 attach 該空間的程序 detach 該空間時,[該空間才會被真正釋放 ](https://www.man7.org/linux/man-pages/man2/shmctl.2.html)。 ``` IPC_RMID Mark the segment to be destroyed. The segment will actually be destroyed only after the last process detaches it (i.e., when the shm_nattch member of the associated structure shmid_ds is zero). The caller must be the owner or creator of the segment, or be privileged. The buf argument is ignored. ``` 因此,當 server 結束時,既有正在運行的 client 依然能夠正常運作,且該共享記憶體空間並不會被釋放。 要解決此問題,作法如同 Problem I ,必須捨棄使用共享記憶體實作 server/client 程式的方式。 ### Problem III - 共享記憶體生命週期問題之二 我在 server 端透過 `shmget` 取得記憶體空間時,加了參數 `IPC_EXCL` 。這是要確保真正獲得一塊新分配的記憶體空間,而不是獲得了某塊可能正在被其他程序使用的空間。我令 server 結束時,透過 `shmctl` 釋放記憶體。 ```c while (1) { int cmd; printf("\n"); printf("1: Show the value\n"); printf("2: Modify the value\n"); printf("3: Exit\n"); printf("Enter commands: "); scanf("%d", &cmd); if (cmd == 1) printf("\033[1;32m[server] The value is %d\033[0m\n", ptr[0]); else if (cmd == 2) { printf("Input new value: "); scanf("%d", &ptr[0]); } else break; } // detach from shared memory shmdt(ptr); // destroy the shared memory shmctl(shmid, IPC_RMID, NULL); ``` 若 server 因為某些原因不正常結束(例如 SIGINT),該記憶體空間將不會被釋放。此時若重新啟動 server , `shmget` 將無法獲得新的記憶體空間,導致 error 。且該未被釋放的共享記憶體空間將造成記憶體洩漏。 要解決此問題,可以在寫程式時實作 signal handler ,或是事後透過 `ipcs` `ipcrm` 等指令手動釋放記憶體空間。 ### Problem IV - 錯誤輸入 若使用者在給予新值時輸入非數字(例如中文),可能導致程式崩壞(例如無窮迴圈等)。要解決此問題,應該在獲取輸入時使用 `fgets` 而非 `printf("%d")` ,然後檢查字串是否為數字,最後再透過 `atoi` 等方法轉成數字。