Паскаль - зомби-процесс остается после форка

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

while True do
  begin
  // Accept connection
  ClientAddrLen := sizeof(ClientAddr);
  ClientSock := fpaccept(ServerSock, @ClientAddr, @ClientAddrLen);

  if ClientSock > 0 then // Success?
    begin

      Pid := fpFork();
      // Error fork
      if pid < 0 then
        begin
          CloseSocket(ClientSock);
          continue;
        end
      // Child process
      else if pid = 0 then
        begin
          CloseSocket(ServerSock);
          handleClient(ClientSock);
          CloseSocket(ClientSock);
          Halt(0);
        end
      // parent process
      else if pid > 0 then
        begin
          CloseSocket(ClientSock);
          continue;
        end;
    end;
end;

Я пишу о функции fpWait() или fpWaitPid(), но в документации по свободному паскалю отсутствуют примеры, и гуглить это бесполезно, поэтому я даже не знаю, как ее использовать. Я использую fpc 2.6.4 на FreeBSD.

Обновление 1 После проб и ошибок, чтения руководств и обсуждений я попробовал несколько комбинаций. Я помещаю следующие функции в родительскую часть исполняемого кода:

else if pid > 0 then
  begin
    CloseSocket(ClientSock);
    //here
    continue;
  end;

а) Использование WaitProcess(pid) (эквивалентно fpWaitPid(pid, @Status, 0))

С этим родительским процессом ждите дочернего процесса, однако, поскольку родительский процесс ждал, он не мог принять другое соединение, пока дочерний процесс не будет завершен.

б) Использование fpWaitPid(pid, @Status, WNOHANG)

Эта функция не блокирует программу, но и ничего делать не мешает. Вроде и функции нет. Это сбивает с толку, потому что везде, где я читал об этом (это было закодировано на C, но это не имеет значения, эти функции являются только оболочками для вызовов unix), предлагалось использовать это.

На данный момент я понятия не имею, что может быть не так. Заранее спасибо.


person Heretiiik    schedule 18.01.2015    source источник
comment
Все эти функции fp* являются обычными функциями unix с префиксом fp, чтобы избежать конфликтов (например, для чтения, записи и открытия).   -  person Marco van de Voort    schedule 18.01.2015
comment
@MarcovandeVoort Хороший вопрос, я провел несколько экспериментов методом проб и ошибок, но, похоже, ничего не работает. Я объясню это в своем вопросе   -  person Heretiiik    schedule 20.01.2015
comment
Я не настоящий эксперт в разветвлении серверов (я предпочитаю многопоточный подход), но я бы дважды проверил, что ваш сценарий соответствует букве скелетов разветвления сервера, возможно, есть необходимость дублировать дескрипторы или какая-то другая дополнительная обработка, которая требуется.   -  person Marco van de Voort    schedule 20.01.2015
comment
@MarcovandeVoort Treads может быть лучшим решением, но я совершенно не знаком с потоками в паскале. Если бы вы могли указать мне правильное направление.   -  person Heretiiik    schedule 22.01.2015
comment
Для сокетов, основанных на многопоточности, логичным направлением было бы повторное использование или, по крайней мере, просмотр некоторых готовых наборов сокетов. В основном indy и synapse и в меньшей степени непереносимые ICS (которые также существуют для Delphi).   -  person Marco van de Voort    schedule 22.01.2015


Ответы (1)


Когда дочерний процесс завершался, он превращался в зомби, и система отправляла сигнал SIGCHLD родительскому процессу. Родительский процесс должен вызывать функцию wait (fpwait в FreePascal), когда принимает сигнал SIGCHLD. Если родительский процесс вызывает функцию wait, система отправляет родительскому процессу код выхода дочернего процесса и стирает его запись и освобождает его pid.

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

procedure DoSigChld;  cdecl;
var stat : longint;
begin
  fpwait(stat);
end;

SignalAction.sa_handler := @DoSigChld;
fpsigaction(SIGCHLD, @SignalAction, nil);
person Anton    schedule 16.10.2015
comment
Это правильный ответ, я не знаю, почему за него проголосовали. Обратите внимание, что настройка действия SIGCHLD на SIG_IGN работает точно так же. См. microhowto.info/howto/. - person Pedro Gimeno; 23.09.2016