Lorsque vfork est appelé, le process parent est-il réellement suspendu?

Autant que je sache quand vfork est appelé process enfant utilise le même espace d'adresse que celui du parent et les modifications apscopes par le process enfant dans les parents sont reflétées sur le process parent. Mes questions sont les suivantes:

  • Lorsque le process enfant est généré, le process parent est-il suspendu?
  • Si oui pourquoi?
  • Ils peuvent fonctionner en parallèle (comme Threads)? Après tout, les threads et le process appellent la même fonction clone() .

Aussi après un peu de search et Goggling j'ai découvert que le process parent n'est pas vraiment suspendu mais que le thread appelant est suspendu. Même si c'est le cas quand le process enfant fait un exit() ou exec() . Comment le process parent sait-il que l'enfant a quitté? Et que se passera-t-il si nous revenons d'un process enfantin?

Votre question est en partie basée sur une mauvaise convention d'appellation. Un «fil de contrôle» dans kernel-speak est un process en langage user. Donc, quand vous lisez ce vfork "le thread appelant est suspendu" penser "process" (ou "thread lourd" si vous le souhaitez) pas "thread" comme dans "process multi-thread".

  • Alors oui, le process parent est suspendu.

vfork sémantique vfork été définie pour le cas très fréquent où un process (le shell le plus souvent) vfork avec certains descripteurs de files, puis exec un autre process en place. Les gens du kernel ont réalisé qu'ils pouvaient économiser une énorme quantité de copys de page en surchargeant la copy, car l' exec allait simplement jeter ces pages copiées. Un enfant vforked a sa propre table de descripteurs de files dans le kernel, donc manipuler cela n'affecte pas le process parent, en gardant la sémantique de fork inchangée.

  • Pourquoi? Parce que fork / exec était courant, cher et gaspillage

Étant donné la définition plus précise du «kernel de contrôle du kernel», la réponse à la question peut-elle s'exécuter en parallèle?

  • Non, le parent sera bloqué par le kernel jusqu'à ce que l'enfant quitte ou exécute

Comment le parent sait-il que l'enfant est sorti?

  • Ce n'est pas le cas, le kernel sait et garde le parent d'get n'importe quel processeur jusqu'à ce que l'enfant soit parti.

En ce qui concerne la dernière question, je soupçonne que le kernel détecte les opérations de la stack enfant impliquées dans un return et signale à l'enfant un signal inaccessible ou simplement le tue, mais je ne connais pas les détails.

Je ne suis pas un programmeur Linux, mais face à la même question aujourd'hui, j'ai fait un test suivant:

 #include<unistd.h> #include<signal.h> #include<errno.h> #include<fcntl.h> #include<cassert> #include<cssortingng> #include<ssortingng> #include<algorithm> #include<vector> #include<map> #include<set> #include<iostream> #include<fstream> #include<sstream> #include<list> using namespace std; int single_talk(int thread_id){ fprintf(stderr,"thread %d before fork @%d\n",thread_id,time(0)); int pid=vfork(); if(-1==pid){ cerr << "failed to fork: " << strerror(errno) << endl; _exit(-3);//serious problem, can not proceed } sleep(1); fprintf(stderr,"thread %d fork returned %d @%d\n",thread_id,pid,time(0)); if(pid){//"CPP" fprintf(stderr,"thread %d in parent\n",thread_id); }else{//"PHP" sleep(1); fprintf(stderr,"thread %d in child @%d\n",thread_id,time(0)); if(-1 == execlp("/bin/ls","ls",(char*)NULL)){ cerr << "failed to execl php : " << strerror(errno) << endl; _exit(-4);//serious problem, can not proceed } } } void * talker(void * id){ single_talk(*(int*)id); return NULL; } int main(){ signal(SIGPIPE,SIG_IGN); signal(SIGCHLD,SIG_IGN); const int thread_count = 44; pthread_t thread[thread_count]; int thread_id[thread_count]; int err; for(size_t i=0;i<thread_count;++i){ thread_id[i]=i; if((err = pthread_create(thread+i,NULL,talker,thread_id+i))){ cerr << "failed to create pthread: " << strerror(err) << endl; exit(-7); } } for(size_t i=0;i<thread_count;++i){ if((err = pthread_join(thread[i],NULL))){ cerr << "failed to join pthread: " << strerror(err) << endl; exit(-17); } } } 

Je l'ai compilé avec g++ -pthread -o repro repro.cpp et exécuté avec ./repro . Ce que je vois dans la sortie est que tout se passe en simultané dans les rounds: d'abord tous les pthreads exécutent vfork, puis tous attendent une seconde, puis se réveillent dans la réalité du process enfant, puis tous les enfants exécutent exec up.

Pour moi, cela prouve que si un pthread appelle un vfork, il ne suspend pas les autres pthreads – s'il le faisait, alors ils ne pourraient pas appeler vfork () s jusqu'à ce que le exec () soit appelé.