Когда vfork называют, родительский процесс действительно приостановлен?

Да, нет абсолютно ничего мешающего Вам выполнить ту команду.

Однако совершенно возможно, что в процессе выполнения его, система станет нестабильной, и Вы получите панику ядра. Я не могу думать ни о чем, что заставило бы это происходить, и я сделал это, не сталкиваясь с упомянутой проблемой, но это теоретически возможно (из-за файлов с отображенной памятью).

Отметьте, хотя, что, как только команда завершается, и Вы роняетесь к оболочке, Вы не сможете сделать единственную вещь.

Другая возможная причина этого сбоя состояла бы в том, если у Вас есть сторожевое выполнение (если Вы не знаете, каков сторожевой таймер, у Вас, вероятно, нет одного). Сторожевой таймер, очень вероятно, перестанет работать, и когда он сделает систему, перезагрузит.

3
08.10.2019, 16:26
4 ответа

Ваш вопрос частично основан на плохом соглашении о присвоении имен. "Поток управления" в ядре - говорит, процесс в пользователе - говорят. Таким образом, когда Вы читаете, что vfork "вызывающий поток приостановлен", думают "процесс" (или "тяжелый поток", если Вам нравится), не, "распараллеливают" как в "многопоточном процессе".

  • Таким образом да, родительский процесс приостановлен.

vfork семантика была определена для очень общего падежа, где процесс (оболочка чаще всего) разветвится, путаница с некоторыми дескрипторами файлов, и затем exec другой процесс на месте. Люди ядра поняли, что они могли сохранить огромный объем копирования страницы наверху, если бы они пропустили копию начиная с exec просто собирался выбросить те скопированные страницы. У vforked ребенка действительно есть его собственная таблица дескрипторов файлов в ядре, таким образом управляя, который не влияет на родительский процесс, сохраняя семантику fork неизменный.

  • Почему? Поскольку ветвление/должностное лицо было распространенным, дорогим, и расточительным

Учитывая более точное определение "потока ядра управления", ответ на может, они работать параллельно ясно

  • Нет, родитель будет заблокирован ядром до дочерних выходов или должностных лиц

Как родитель знает, что ребенок вышел?

  • Это не делает, ядро знает и мешает родителю получать любой ЦП вообще, пока ребенок не ушел.

Что касается последнего вопроса, я подозревал бы, что ядро будет обнаруживать дочерние операции стека, вовлеченные в возврат, и сигнализировать ребенку с неуловимым сигналом или просто уничтожать его, но я не знаю детали.

2
27.01.2020, 21:23
  • 1
    Вы уверенный в этом? Я записал довольно простую программу (все же слишком долго для вставки здесь), который создает 40 pthreads, выполняет vfork в каждом из них и должностное лицо если pid=0 в каждом дочернем процессе, работая 2x сон (1) между vfork и должностным лицом, и регистрируя каждый шаг. Я вижу в журналах, что все vforks обрабатываются в пакетном режиме вместе, затем приезжайте весь "midsteps" и затем все должностные лица. Единственное объяснение, которое я вижу к этому, состоит в том, что другие pthreads не приостанавливаются, когда vfork называют. –  qbolec 23.10.2014, 13:57
  • 2
    Да, это корректно. Ваш тестовый код содержит действия, которые Вы не полностью понимаете, в особенности как sleep() реализован. –  msw 23.10.2014, 19:41

Я не программист линукса, но столкнувшись сегодня с тем же вопросом, я сделал следующий тест:

#include<unistd.h>
#include<signal.h>
#include<errno.h>
#include<fcntl.h>
#include<cassert>
#include<cstring>
#include<string>
#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);
    }
  }
}

Я скомпилировал его с g++ -pthread -o repro.cpp и запустил с ./repro. Что я вижу на выходе, так это то, что всё происходит одновременно в раундах: сначала все pthreads запускают vfork, потом все ждут секунду, потом "просыпаются" в дочерней процессной реальности, потом все дети запускают exec(), потом наконец-то просыпаются все родители.

Для меня это доказывает, что если один из pthread'ов вызывает vfork, то он не приостанавливает работу других pthread'ов - если бы это было так, то они не смогли бы вызвать vfork() до тех пор, пока не будет вызвана функция exec().

1
27.01.2020, 21:23

When child process is spawned is parent process suspended?

Да.

If yes why?

Поскольку родительский и дочерний узлы используют совместное адресное пространство. В частности, адресное пространство стека. Если родитель попытается продолжить, он, скорее всего, вызовет другую функцию и уничтожит стек вызовов дочернего процесса. Таким образом, он не запускается до exec()или _exit()

.

They can run in parallel (like Threads)? After all both threads and process call the same clone() function.

Действительно. Приостанавливается только вызывающий поток. См. выше.

How does parent process know that the child has exited?

Он вызывает wait4(). Но скорее вы спрашиваете, откуда родитель знает, что нужно продолжать. Это не так. Ядро делает его снова работоспособным, когда происходит любое из двух определенных событий.

And what will happen if we return from a child process?

vfork()возвращается в освобожденный кадр стека, а следующий return;— это быстрый путь к неопределенному поведению.

0
27.01.2020, 21:23

What will happen if we return from a child process?

«Это действительно не работает, однако, чтобы вернуться во время работы в контексте ребенка из процедура, которая вызвала vfork ()с момента возможного возврата из vfork ()затем вернется к несуществующему кадру стека."

Я не понимаю это буквально. Байты в области стека буквально не исчезают после каждой инструкции POP (или RETURN ). Однако если вы вернетесь, продолжите работу и выполните инструкцию PUSH (или CALL ), она заменит предыдущее значение в стеке.

Это всего лишь один яркий пример странных вещей, которые произойдут в целом.если вы вызовете vfork(), а затем сделаете что-нибудь, чтобы изменить какую-либо часть памяти вашего процесса.

[Технически я предполагаю то же поведение, что и в Linux. Другое поведение vfork ()было технически разрешено POSIX. Я не знаю, нашел ли кто-нибудь применение технической гибкости POSIX, кроме предоставления vfork (), который идентичен fork ()].

0
27.01.2020, 21:23

Теги

Похожие вопросы