3

C プログラムを OpenVMS から Linux に移行する必要があり、サブプロセスを生成するプログラムで問題が発生しています。サブプロセスが生成されます (fork は正常に動作します) が、execve は失敗します (間違ったプログラム名が指定されているため、これは正しいことです)。

しかし、アクティブなサブプロセスの数をリセットするために、後で wait() を呼び出しますが、戻りません。ps 経由でプロセスを見ると、これ以上サブプロセスがないことがわかりますが、wait() は思ったように ECHILD を返しません。

while (jobs_to_be_done)
{
   if (running_process_cnt < max_process_cnt)
   {
      if ((pid = vfork()) == 0)
      {
         params[0] = param1 ;
         params[1] = NULL ;
         if ((cstatus = execv(command, params)) == -1)
         {
            perror("Child - Exec failed") ;   // this happens
            exit(EXIT_FAILURE) ;
         }
      }
      else if (pid < 0)
      {
         printf("\nMain - Child process failed") ;
      }
      else
      {
         running_process_cnt++ ;
      }
   }
   else   // no more free process slot, wait
   {
      if ((pid = wait(&cstatus)) == -1)   // does not return from this statement
      {
         if (errno != ECHILD)
         {
            perror("Main: Wait failed") ;
         }
         anz_sub = 0 ;
      }
      else
      {
         ...
      }
   }
}

サブプロセスがもうないことを待機コマンドに伝えるために何かしなければならないことはありますか? OpenVMS では、プログラムは正常に動作します。

ご協力ありがとうございました

4

2 に答える 2

2

Linux カーネルの遅延コピー オン ライト技術のおかげで、 fork(2)vforkは十分に効率的であるため、最近の Linux での使用はお勧めしません。

の結果を確認する必要がありforkます。失敗していない限り、プロセスは作成されており、wait(またはwaitpid(2)、おそらくWNOHANG実際に待ちたくない場合は、すでに終了した子プロセスについて調べるだけで...)失敗することはありません(たとえ子のexec関数は失敗し、フォークは成功しました)。

シグナルを慎重に使用することもできます。 signal(7)SIGCHLDを参照してください。シグナルを使用する防御的な方法は、シグナル ハンドラーで何らかのフラグを設定し、ループ内でこれらのフラグをテストしてクリアすることです。非同期シグナルセーフ関数 (およびそれらの数はかなり少ない) のみが、シグナルハンドラー内で (間接的であっても) 呼び出すことができることを思い出してください。POSIX シグナルについてもお読みください。volatile sigatomic_t

時間を取ってAdvanced Linux Programmingを読んで、より広い視野を持ってください。POSIX で OpenVMS を模倣しようとするのではなく、POSIX または Linux の方法で考えてください。

waitpidおそらく、(時々または常に) を使用して、常にループに入れたいと思うかもしれませんWNOHANG。そのwaitpidため、else 部分だけでなくif (running_process_cnt < max_process_cnt)、おそらくループのすべての繰り返しで呼び出す必要があります。

すべての警告とデバッグ情報 ( gcc -Wall -Wextra -g) を使用してコンパイルしてから、gdbデバッガーを使用することをお勧めします。プログラムをstrace(1)することもできます (おそらく-f)

メモリーのオーバーコミットについて学びたいと思うかもしれません。私はこの機能が嫌いで、通常は無効にしています (たとえば、echo 0 > /proc/sys/vm/overcommit_memoryroot として実行するなど)。proc(5)も参照してください- これは知っておくと非常に便利です...

于 2015-07-21T06:56:11.200 に答える
1

からman vfork:

子は現在の関数から戻ったり、exit(3) を呼び出したりしてはなりませんが、_exit(2) を呼び出すことはできます。

(after )exit()への呼び出しが失敗したときに呼び出してはなりません。代わりに使用する必要があります。これだけで、戻ってこないという問題が発生している可能性は十分にあります。execvvfork_exit()wait

forkの代わりに使用することをお勧めしますvfork。はるかに簡単で安全に使用できます。

それだけで問題が解決しない場合は、原因が見つかるまでデバッグを行うか、コードを削減する必要があります。たとえば、次はハングせずに実行する必要があります。

#include <sys/wait.h>

int main(int argc, char ** argv)
{
    pid_t pid;
    int cstatus;
    pid = wait(&cstatus);
    return 0;
}

このプログラムがハングしないことを確認できた場合、ハングの原因はプログラムの何らかの側面にあるはずです。への呼び出しの直前と直後に print ステートメントを入れることをお勧めしますwait

于 2015-07-21T07:52:20.327 に答える