[英]Why would I need threads for implementing a 'named pipe based on shared memory'?
在嘗試實現Named pipe
(例如,使用相同共享內存的兩個獨立的不相關進程)時,我一直在閱讀要使用pthread_atfork
和atexit
。
我完全同意互斥量和信號量的使用-使用它們,我們可以決定process A
何時讀/寫以及process B
何時讀/寫。
但是出於什么原因,我想為此使用pthread_atfork
和線程?
編輯:
一個不使用信號量的示例將耗資巨大:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/times.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <assert.h>
// Simple busy-wait loop to throw off our timing.
void busywait(void)
{
clock_t t1 = times(NULL);
while (times(NULL) - t1 < 2);
}
int main(int argc, char *argv[])
{
const char *message = "Hello World\n";
int n = strlen(message) / 2;
pid_t pid = fork();
int i0 = (pid == 0) ? 0 : n;
int i;
for (i = 0; i < n; i++) {
write(1, message + i0 + i, 1);
busywait();
}
}
沒有人說過必須使用線程來實現命名管道。 但是您的庫代碼可以在線程化的項目中使用,因此您可以處理許多特殊情況。 您可能已經知道,SysV IPC對象(如共享內存段)在其使用計數降至0
時不會自動刪除,除非已將其標記為銷毀。 這意味着,如果程序使用您的代碼創建管道,然后由於任何原因導致崩潰,則管道實施中的IPC對象很可能會保留下來,污染IPC名稱空間,並消耗寶貴的系統資源。
您提到的兩個函數pthread_atfork()
和atexit()
用於注冊在某些情況發生時執行的回調。 每當進程以正常方式終止時(例如,通過調用exit(3)
或從main()
返回exit(3)
atexit()
注冊要執行的代碼。 這使您可以發現未顯式關閉管道的情況,並進行必要的清理。
除了在不關閉管道的情況下退出進程之外,該程序還可能會派生自己。 這也是一種特殊情況,您必須相應地處理。 pthread_atfork()
應該在進行分叉時注冊要在各個點調用的三個回調。
您可能還應該處理某些OS信號,這些信號可能最終未被捕獲,從而可能在執行適當的清理之前終止程序。
如您所見,編寫庫比編寫程序要復雜得多。 在編寫程序時,您可以控制(幾乎)所有用例。 當您編寫庫時,可能會在許多不同的場景中使用它,並且您應該考慮所有內容並為所有內容做好准備。 您應該考慮正確的用法和不正確的用法。 您應該考慮清理之類的問題,以及如果未正確使用您的庫可能會殘留哪些系統資源。 等等等等...
大致來說,類似管道的結構應位於共享內存中(例如,通過shm_open
獲得),並包含以下成員:
讀取功能基本上應該獲取互斥體,然后檢查是否有可讀取的數據,如果沒有,請等待條件變量並循環檢查數據。 找到數據后,如果讀取使得有可能在緩沖區中容納更多數據以喚醒可能正在等待的寫入器,則需要向條件變量發送信號。 將讀取的數據復制到調用方提供的緩沖區中,然后解鎖互斥鎖。
寫功能基本上應該獲取互斥體,然后檢查緩沖區中是否還有剩余空間要寫。 如果沒有,它應該等待條件變量並循環檢查可用空間。 找到空間后,它應該將數據復制到緩沖區中,向條件變量發出信號以喚醒可能正在等待數據的任何讀取器,然后解鎖互斥鎖。
互斥量和條件變量都需要使用進程共享屬性創建,您將使用“管道”在進程之間進行通信(而不僅僅是同一進程中的線程)。 您可能還需要考慮是否要支持多個讀取器/寫入器以及條件變量是否需要單信號或廣播信號語義。 有很多方法可以優化行為,但是上面的概述應該為您提供一個一般的起點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.