程式間通訊如何加鎖
關於程式間的通訊方式估計大多數人都知道,這也是常見的面試八股文之一。
個人認為這種面試題沒什麼意義,無非就是答幾個關鍵詞而已,更深入的可能面試官和麵試者都不太瞭解。
關於程式間通訊方式和優缺點我之前在【這篇文章】中有過介紹,感興趣的可以移步去看哈。
程式間通訊有一種[共享記憶體]方式,大家有沒有想過,這種通訊方式中如何解決資料競爭問題?
我們可能自然而然的就會想到用鎖。但我們平時使用的鎖都是用於解決執行緒間資料競爭問題,貌似沒有看到過它用在程式中,那怎麼辦?
我找到了兩種方法,訊號量和互斥鎖。
直接給大家貼程式碼吧,首先是訊號量方式:
#include#include#include#include#include#include#include#include#include#includeconstexpr int kMappingSize = 4096; void sem() { const char* mapname = "/mapname"; int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); MEOW_DEFER { if (mapfd > 0) { close(mapfd); mapfd = 0; } shm_unlink(mapname); }; if (mapfd == -1) { perror("shm_open failed \n"); exit(EXIT_FAILURE); } if (ftruncate(mapfd, kMappingSize) == -1) { perror("ftruncate failed \n"); exit(EXIT_FAILURE); } void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0); if (!sp) { perror("mmap failed \n"); exit(EXIT_FAILURE); } sem_t* mutex = (sem_t*)sp; if (sem_init(mutex, 1, 1) != 0) { perror("sem_init failed \n"); exit(EXIT_FAILURE); } MEOW_DEFER { sem_destroy(mutex); }; int* num = (int*)((char*)sp + sizeof(sem_t)); int cid, proc_count = 0, max_proc_count = 8; for (int i = 0; i < max_proc_count; ++i) { cid = fork(); if (cid == -1) { perror("fork failed \n"); continue; } if (cid == 0) { sem_wait(mutex); (*num)++; printf("process %d : %d \n", getpid(), *num); sem_post(mutex); if (munmap(sp, kMappingSize) == -1) { perror("munmap failed\n"); } close(mapfd); exit(EXIT_SUCCESS); } ++proc_count; } int stat; while (proc_count--) { cid = wait(&stat); if (cid == -1) { perror("wait failed \n"); break; } } printf("ok \n"); }
程式碼中的MEOW_DEFER我在之前的RAII相關文章中介紹過,它內部的函式會在生命週期結束後觸發。它的核心函式其實就是下面這四個:
int sem_init(sem_t *sem,int pshared,unsigned int value); int sem_post(sem_t *sem); int sem_wait(sem_t *sem); int sem_destroy(sem_t *sem);
具體含義大家應該看名字就知道,這裡的重點就是sem_init中的pshared引數,該引數為1表示可在程式間共享,為0表示只在程式內部共享。
第二種方式是使用鎖,即pthread_mutex_t,可是pthread_mutex不是用作執行緒間資料競爭的嗎,怎麼能用在程式間呢?
我也是最近才知道,可以給它配置一個屬性,示例程式碼如下:
pthread_mutex_t* mutex; pthread_mutexattr_t mutexattr; pthread_mutexattr_init(&mutexattr); pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(mutex, &mutexattr);
它的預設屬性是程式內私有,但是如果給它配置成PTHREAD_PROCESS_SHARED,它就可以用在程式間通訊中。
完整程式碼如下:
void func() { const char* mapname = "/mapname"; int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); MEOW_DEFER { if (mapfd > 0) { close(mapfd); mapfd = 0; } shm_unlink(mapname); }; if (mapfd == -1) { perror("shm_open failed \n"); exit(EXIT_FAILURE); } if (ftruncate(mapfd, kMappingSize) == -1) { perror("ftruncate failed \n"); exit(EXIT_FAILURE); } void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0); if (!sp) { perror("mmap failed \n"); exit(EXIT_FAILURE); } pthread_mutex_t* mutex = (pthread_mutex_t*)sp; pthread_mutexattr_t mutexattr; pthread_mutexattr_init(&mutexattr); pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(mutex, &mutexattr); MEOW_DEFER { pthread_mutexattr_destroy(&mutexattr); pthread_mutex_destroy(mutex); }; int* num = (int*)((char*)sp + sizeof(pthread_mutex_t)); int cid, proc_count = 0, max_proc_count = 8; for (int i = 0; i < max_proc_count; ++i) { cid = fork(); if (cid == -1) { perror("fork failed \n"); continue; } if (cid == 0) { pthread_mutex_lock(mutex); (*num)++; printf("process %d : %d \n", getpid(), *num); pthread_mutex_unlock(mutex); if (munmap(sp, kMappingSize) == -1) { perror("munmap failed\n"); } close(mapfd); exit(EXIT_SUCCESS); } ++proc_count; } int stat; while (proc_count--) { cid = wait(&stat); if (cid == -1) { perror("wait failed \n"); break; } } printf("ok \n"); }
我想這兩種方式應該可以滿足我們日常開發過程中的大多數需求。
鎖的方式介紹完之後,可能很多朋友自然就會想到原子變數,這塊我也搜尋了一下。但是也不太確定C++標準中的atomic是否在程式間通訊中有作用,不過看樣子boost中的atomic是可以用在程式間通訊中的。
其實在研究這個問題的過程中,還找到了一些很多解決辦法,包括:
- Disabling Interrupts
- Lock Variables
- Strict Alternation
- Peterson's Solution
- The TSL Instruction
- Sleep and Wakeup
- Semaphores
- Mutexes
- Monitors
- Message Passing
- Barriers
這裡就不過多介紹啦,大家感興趣的可以自行查閱資料哈。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2855681/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux程式之間如何通訊?Linux
- PHP程式間通訊PHP
- 程式間通訊——LINUXLinux
- 程式間通訊(Socket)
- 程式間的通訊
- Linux程式間通訊Linux
- 什麼是程式間通訊?Linux程式間通訊有幾種方式?Linux
- 程式間通訊是什麼?Linux程式間通訊有幾種方式?Linux
- IPC-程式間通訊
- 程式間通訊簡介
- Android 程式之間通訊Android
- Linux程式間通訊-eventfdLinux
- 程式間通訊--訊息佇列佇列
- linux 程式間通訊之管道Linux
- 程式間通訊的場景
- Linux 的程式間通訊:管道Linux
- linux 程式間通訊之FIFOLinux
- Android程式間通訊詳解Android
- 實驗八 程式間通訊
- 程式間通訊方式有哪些?
- 通過 App Groups 實現程式間通訊APP
- linux程式間通訊(IPC)小結Linux
- Electron實戰之程式間通訊
- Linux程式間通訊②:有名管道FIFOLinux
- Android程式間通訊,AIDL工作原理AndroidAI
- 微服務的程式間通訊(IPC)微服務
- 程式間的幾種通訊方式
- linux程式間通訊--管道(PIPE & FIFO)Linux
- Linux 程式間通訊之System V 訊號量Linux
- 程式間通訊——XSI IPC之訊息佇列佇列
- Aidl程式間通訊詳細介紹AI
- 溫故之.NET程式間通訊——管道
- 在 OpenResty 裡實現程式間通訊REST
- 實現不同程式之間的通訊
- 程式間通訊之共享記憶體記憶體
- Android程式間通訊(複習筆記)Android筆記
- 論加鎖否:程式日誌
- 程序間的通訊(訊號通訊)