2009-10-05 6 views
10

Jeder kennt das klassische Modell eines Prozesses, der nach Verbindungen auf einem Socket lauscht und einen neuen Prozess für jede neue Verbindung abfängt. Üblicherweise ruft der Elternprozess sofort close auf dem neu erstellten Socket auf, wodurch die Anzahl der Handle verringert wird, sodass nur das Kind über einen Handle für den neuen Socket verfügt.Erzeugt ein neuer Thread doppelte Dateideskriptoren und Socketdeskriptoren in Linux?

Ich habe gelesen, dass die einzige Unterschied zwischen einem Prozess und einem Thread in Linux ist, dass Threads den gleichen Speicher teilen. In diesem Fall nehme ich an, dass das Erstellen eines neuen Threads, um eine neue Verbindung zu behandeln, auch die Dateideskriptoren dupliziert und außerdem den "übergeordneten" Thread benötigt, um die Kopie des Sockets zu schließen.

+0

"Ich habe gelesen, dass der einzige Unterschied zwischen einem Prozess und einem Thread in Linux ist, dass Threads den gleichen Speicher teilen. *" Es gibt viele andere Unterschiede zwischen Prozessen und Threads. Zum Beispiel können Prozesse mehr als einen Thread enthalten. –

Antwort

8

Nein. Threads teilen sich den gleichen Speicher, also teilen sie dieselben Variablen. Wenn Sie den Socket im übergeordneten Thread schließen, wird er auch im untergeordneten Thread geschlossen.

EDIT:

  • Mann Gabel: Das Kind erbt Kopien der Satz der Eltern der geöffneten Dateibeschreibungen.

  • Mann pThreads: Themen Aktien eine Reihe anderer Eigenschaften (dh sind diese Attribute Prozess weit statt pro Thread): [...] Deskriptoren für offene Dateien

Und einige Code:

#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); 
} 

Ausgang ist:

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

Haben Sie eine Referenz? –

+0

Ich habe es nicht hier bei der Arbeit, aber ich kann meine Kopie von Stevens 'UNPv2 nach Hause kommen. –

+0

@Shelby - Danke, ich habe eine Kopie von UNP, aber habe nur ungefähr ein Drittel gelesen. –

9

Auf Linux-Themen werden über die clone syscall mit dem CLONE_FILES Flag implementiert:

Wenn CLONE_FILES gesetzt, der anruf Prozess und die Kindprozesse teilen die gleiche Datei Deskriptortabelle. Jeder Dateideskriptor, der vom aufrufenden Prozess oder vom untergeordneten Prozess erstellt wird, ist , der auch im anderen Prozess gültig ist. Wenn einer der Prozesse einen Dateideskriptor schließt oder seine zugehörigen Flags ändert (unter Verwendung der fcntl (2) F_SETFD-Operation), wird der andere -Prozess ebenfalls beeinflusst.

haben auch einen Blick auf die glibc-Quellcode für die Details, wie es in createthread.c verwendet wird:

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

Grundsätzlich Linux-Klon() kann implementieren nicht nur einen neuen Prozess (wie Gabel()), oder ein neuer Thread (wie pthread_create vielleicht), aber auch alles dazwischen.

In der Praxis wird es immer nur für das eine oder andere verwendet. Threads, die mit pthread_create erstellt wurden, teilen die Dateideskriptoren mit allen anderen Threads im Prozess (nicht nur dem übergeordneten). Dies ist nicht verhandelbar.

Die Freigabe eines Dateideskriptors und einer Kopie ist anders.Wenn Sie eine Kopie haben (wie fork()), müssen alle Kopien geschlossen werden, bevor das Datei-Handle verschwindet. Wenn Sie die FD in einem Thread teilen, ist es weg, sobald Sie es geschlossen haben.