2009-10-05 259 views
10

每個人都知道進程監聽套接字上的連接的經典模型,並分派一個新進程來處理每個新連接。通常的做法是讓父進程立即在新創建的套接字上調用close,遞減句柄計數以便只有子對象具有新套接字的句柄。在Linux中創建新線程是否重複文件描述符和套接字描述符?

我讀過唯一的區別 Linux中的進程和線程之間是線程共享相同的內存。在這種情況下,我假設產生一個新的線程來處理一個新的連接也複製文件描述符,並且還需要'父'線程關閉它的套接字的副本?

+0

「我讀過Linux中進程和線程之間唯一的區別是線程共享相同的內存。」進程和線程之間還有很多其他差​​異。例如,進程可以包含多個線程。 – 2017-01-03 15:52:59

回答

8

編號線程共享相同的內存,因此它們共享相同的變量。如果關閉父線程中的套接字,它也將在子線程中關閉。

編輯:

  • 人叉:孩子繼承複製打開文件描述符的父母的一套

  • 人並行線程:線程份額一系列其他的屬性(即,這些屬性是進程範圍,而不是每個線程):[...]打開文件描述符

有些代碼:

#include <cstring> 
#include <iostream> 
using namespace std; 

#include <errno.h> 
#include <fcntl.h> 
#include <pthread.h> 
#include <unistd.h> 

// global variable 
int fd = -1; 

void * threadProc(void * param) { 
    cout << "thread: begin" << endl; 
    sleep(2); 
    int rc = close(fd); 
    if (rc == -1) { 
     int errsv = errno; 
     cout << "thread: close() failed: " << strerror(errsv) << endl; 
    } 
    else { 
     cout << "thread: file is closed" << endl; 
    } 
    cout << "thread: end" << endl; 
} 

int main() { 
    int rc = open("/etc/passwd", O_RDONLY); 
    fd = rc; 

    pthread_t threadId; 
    rc = pthread_create(&threadId, NULL, &threadProc, NULL); 

    sleep(1); 

    rc = close(fd); 
    if (rc == -1) { 
     int errsv = errno; 
     cout << "main: close() failed: " << strerror(errsv) << endl; 
     return 0; 
    } 
    else { 
     cout << "main: file is closed" << endl; 
    } 

    sleep(2); 
} 

輸出是:

thread: begin 
main: file is closed 
thread: close() failed: Bad file descriptor 
thread: end 
+0

你有參考嗎? – 2009-10-05 20:05:17

+0

我在這裏工作時沒有和我在一起,但是一旦我回家,我可以查看Stevens'UNPv2的副本。 – 2009-10-05 20:09:33

+0

@Shelby - 謝謝,我有一份UNP,但只讀了三分之一。 – 2009-10-05 20:18:49

9

在Linux線程通過使用CLONE_FILES標誌clone系統調用來實現:

如果CLONE_FILES設置,主叫 進程和子進程共享 相同的文件描述符表。由調用 進程或子進程創建的任何 文件描述符也是 在其他進程中也是有效的。 同樣,如果其中一個進程 關閉了文件描述符,或者更改了其關聯的標誌(使用 fcntl(2)F_SETFD操作),其他 進程也受到影響。

而且看看對細節的glibc的源代碼,它是如何在createthread.c使用:

int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL 
      | CLONE_SETTLS | CLONE_PARENT_SETTID 
      | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM 
#if __ASSUME_NO_CLONE_DETACHED == 0 
      | CLONE_DETACHED 
#endif 
      | 0); 
8

原則上,Linux的克隆()不僅可以實現一個新的進程(如叉()),或者一個新的線程(也許像pthread_create),但也包括其中的任何東西。

實際上,它只能用於其中之一。使用pthread_create創建的線程與進程中的所有其他線程共享文件描述符(而不僅僅是父級)。這是不可談判的。

共享文件描述符並擁有一個副本是不同的。如果您有副本(如fork()),則在文件句柄消失之前,必須關閉所有副本。如果你在一個線程中共享FD,一旦關閉它,它就消失了。