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

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

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

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

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

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

Ваш вопрос частично основан на плохом соглашении о присвоении имен. "Поток управления" в ядре - говорит, процесс в пользователе - говорят. Таким образом, когда Вы читаете, что 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

Теги

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