WeHelp
C 語言可以直接呼叫作業系統提供的 System Call 且速度極快,用來開發基礎系統程式非常適合。
  1. C 系統程式
  2. C 檔案寫入、讀取
  3. Process 程序管理
  4. Thread 執行緒管理
  5. IPC 程序間通訊
  6. PIPE 程序間通訊
  7. FIFO 程序間通訊
  8. 共享記憶體通訊
  9. Socket 程序間通訊
  10. TCP 網路連線
共享記憶體通訊
## IPC Shared Memory 簡介 Shared Memory(共享記憶體)是一種 IPC(Inter-Process Communication,行程間通訊)機制,讓多個行程將同一段實體記憶體映射到自己的虛擬位址空間,直接讀寫其中資料。 ### 主要特性 - **速度快**:資料直接位於共享記憶體中,不需要像 Pipe 或 Socket 一樣反覆複製資料。 - **可供多個行程存取**:不同 Process 可將同一段記憶體映射到自己的位址空間。 - **需要同步機制**:Shared Memory 本身不提供互斥或同步功能,若多個行程同時讀寫,可能發生 Race Condition,通常要搭配: - Semaphore - Mutex(需配置在 shared memory 中,且設定為 process-shared) - File lock - 其他同步機制 - **生命週期由核心管理**:以 System V Shared Memory 為例,記憶體區段會由核心管理,必須明確移除。 - **資料格式由程式自行定義**:Shared Memory 只是一塊記憶體,不會自動處理字串、結構或訊息邊界。 --- ## System V Shared Memory 常用 System Call C 程式通常透過以下函式使用 System V Shared Memory: ### 1. `shmget()` 建立或取得共享記憶體區段。 ```c int shmget(key_t key, size_t size, int shmflg); ``` 常見參數: - `key`:共享記憶體的識別鍵 - `size`:共享記憶體大小 - `shmflg`: - `IPC_CREAT`:不存在時建立 - `0666`:權限設定 成功時回傳 Shared Memory ID,失敗回傳 `-1`。 --- ### 2. `shmat()` 將共享記憶體附加(attach)到目前行程的位址空間。 ```c void *shmat(int shmid, const void *shmaddr, int shmflg); ``` 通常使用: ```c char *data = shmat(shmid, NULL, 0); ``` 成功時回傳映射後的位址,失敗時回傳 `(void *) -1`。 --- ### 3. `shmdt()` 將共享記憶體從目前行程的位址空間分離(detach)。 ```c int shmdt(const void *shmaddr); ``` 這只代表目前行程不再使用該記憶體,不一定會刪除共享記憶體區段。 --- ### 4. `shmctl()` 控制或刪除共享記憶體。 ```c int shmctl(int shmid, int cmd, struct shmid_ds *buf); ``` 刪除共享記憶體: ```c shmctl(shmid, IPC_RMID, NULL); ``` 通常流程為: ```text shmget() → shmat() → 讀寫資料 → shmdt() → shmctl(IPC_RMID) ``` --- ## 簡單範例:Parent 與 Child 透過 Shared Memory 通訊 以下程式建立一段共享記憶體,Parent 與 Child 透過 `fork()` 共用它: - Child 寫入一段訊息 - Parent 等待 Child 結束後讀取訊息 - 最後 Parent 清除共享記憶體 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include <unistd.h> #define SHM_SIZE 1024 int main(void) { int shmid; char *shared_data; pid_t pid; /* * IPC_PRIVATE 表示建立一個新的共享記憶體區段。 * 0666 為讀寫權限。 */ shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666); if (shmid == -1) { perror("shmget"); exit(EXIT_FAILURE); } /* * 將共享記憶體附加到目前行程。 */ shared_data = shmat(shmid, NULL, 0); if (shared_data == (void *)-1) { perror("shmat"); shmctl(shmid, IPC_RMID, NULL); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork"); shmdt(shared_data); shmctl(shmid, IPC_RMID, NULL); exit(EXIT_FAILURE); } if (pid == 0) { /* Child:寫入共享記憶體 */ strcpy(shared_data, "Hello from child process!"); printf("Child: message written to shared memory.\n"); shmdt(shared_data); exit(EXIT_SUCCESS); } else { /* Parent:等待 Child 完成 */ waitpid(pid, NULL, 0); printf("Parent received: %s\n", shared_data); /* Parent 不再使用共享記憶體 */ shmdt(shared_data); /* 標記刪除共享記憶體區段 */ shmctl(shmid, IPC_RMID, NULL); } return 0; } ``` ### 編譯與執行 ```bash gcc -Wall -o shm_example shm_example.c ./shm_example ``` 可能輸出: ```text Child: message written to shared memory. Parent received: Hello from child process! ``` ## 注意事項 上述範例使用 `waitpid()`,因此 Parent 會等 Child 寫入完成後才讀取,所以不會發生同步問題。但在實際應用中,如果兩個行程同時持續讀寫 Shared Memory,就必須搭配 Semaphore 或其他同步機制。 另外,System V Shared Memory 和 POSIX Shared Memory 是兩種常見介面: - System V:`shmget()`、`shmat()`、`shmdt()`、`shmctl()` - POSIX:`shm_open()`、`ftruncate()`、`mmap()`、`munmap()`、`shm_unlink()` 兩者都能實現共享記憶體,但 API 與生命週期管理方式不同。
相關學習地圖、教學課程
C 語言,系統程式
掌握基礎的 C 語法,以及進階的系統程式開發能力。