2009-10-05 14 views
10

Todo el mundo conoce el modelo clásico de un proceso que escucha las conexiones en un socket y bifurca un nuevo proceso para manejar cada nueva conexión. La práctica normal es que el proceso principal llame inmediatamente al close en el socket recién creado, disminuyendo el número de identificadores para que solo el niño tenga un identificador para el nuevo socket.¿Crea un nuevo subproceso descriptores de archivos duplicados y descriptores de socket en Linux?

He leído que única diferencia entre un proceso y un hilo en Linux es que los hilos comparten la misma memoria. En este caso, supongo que al generar un nuevo hilo para manejar una nueva conexión también se duplican los descriptores de los archivos y también se requerirá que el hilo 'padre' cierre su copia del socket.

+0

"* He leído que la única diferencia entre un proceso y un hilo en Linux es que los hilos comparten la misma memoria. *" Hay muchas otras diferencias entre los procesos y los hilos. Por ejemplo, los procesos pueden contener más de un hilo. –

Respuesta

8

No. Los subprocesos comparten la misma memoria, por lo que comparten las mismas variables. Si cierra el socket en el subproceso principal, también se cerrará en el subproceso secundario.

EDIT:

  • hombre tenedor: el niño hereda copias del conjunto de descriptores de archivos abiertos de los padres.

  • hombre pthreads: Temas comparten una serie de otros atributos (es decir, estos atributos son en todo el proceso y no por subproceso): [...] descriptores de archivos abiertos

Y algunos código:

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

de salida es:

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

¿Tiene una referencia? –

+0

No lo tengo conmigo aquí en el trabajo, pero puedo verificar mi copia de la UNPv2 de Stevens una vez que llegue a casa. –

+0

@Shelby - Gracias, tengo una copia de UNP pero solo he llegado a leer acerca de un tercio de ella. –

9

En las discusiones de Linux se apliquen a través del clone llamada al sistema usando la bandera CLONE_FILES:

Si CLONE_FILES se establece, el proceso de llamada y los procesos hijo comparten el mismo tabla de descriptores de archivo. Cualquier descriptor de archivo creado por el proceso de llamada o por el proceso secundario es también válido en el otro proceso. Del mismo modo, si uno de los procesos cierra un descriptor de archivo o cambia sus indicadores asociados (utilizando la operación fcntl (2) F_SETFD), el otro proceso también se ve afectado.

también tienen un vistazo al código fuente de glibc para los detalles de cómo se utiliza en 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

En principio, el clon de Linux() se puede aplicar no sólo un nuevo proceso (como tenedor()), o un nuevo hilo (como pthread_create quizás), pero también cualquier cosa intermedia.

En la práctica, solo se utiliza para uno u otro. Los subprocesos creados con pthread_create comparten los descriptores de archivo con todos los otros subprocesos en el proceso (no solo el principal). Esto no es negociable

Compartir un descriptor de archivo y tener una copia es diferente.Si tiene una copia (como fork()), todas las copias deben cerrarse antes de que desaparezca el identificador del archivo. Si compartes el FD en un hilo, una vez que uno lo cierra, se va.

Cuestiones relacionadas