Linuxシステムプログラミング38プロセス制御-exec関数ファミリは、fork + execl + waitを使用してfflushを追加する必要があります

実験1:execlを使用し、ストリームを更新するにはfflush()を追加する必要があります
実験2:fork()execl()wait()を組み合わせて使用

少数:フォーク+実行+待機

はじめに:
次のプログラムを実行し、ps axfコマンドを実行して、次の親子プロセスの関係を表示します。

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

#define LEFT 200
#define RIGHT 250

int main(void)
{
	int i,j,mark;
	pid_t pid;
	
	for(i = LEFT; i <= RIGHT; i++)
	{
		pid = fork();
		if(pid < 0)
		{
			fprintf(stderr,"fork() failed!\n");
			exit(1);
		}
		else if(pid == 0)//child
		{
			mark = 1;
			for(j = 2; j < i/2; j++)
			{
				if(i % j ==0)
					{
						mark = 0;
						break;
					}
			
			}

			if(mark)
				printf("%d is a primer\n",i);

			exit(0);//!!!
		}
		
	}

	sleep(1000);
	exit(0);
}


  2837 pts/0    Ss     0:01          |   \_ /bin/bash
 26731 pts/0    S+     0:00          |   |   \_ ./a.out
 26732 pts/0    Z+     0:00          |   |       \_ [a.out] <defunct>
 26733 pts/0    Z+     0:00          |   |       \_ [a.out] <defunct>
 26734 pts/0    Z+     0:00          |   |       \_ [a.out] <defunct>
 26735 pts/0    Z+     0:00          |   |       \_ [a.out] <defunct>
....


シェルプロセスが
a.outプロセスの親プロセスであることがわかります。a.out親プロセスは残りの201個のa.outプロセスの親プロセスです。

質問1:シェルプロセスとa.outプロセスの関係について

そこで問題が発生します。a.outと彼がフォークする201a.outsの関係は簡単に理解できます。しかし、シェルプロセスとa.outの親プロセスの関係を理解するにはどうすればよいでしょうか。
親プロセスと子プロセスの関係は、親プロセス自体をコピーして子プロセスを取得することであることを以前に学びました。fork()の後、子プロセスと親プロセスのコードと実行位置はまったく同じです。親プロセスと子プロセスがダウンすることを除いて、実行されると、IDに従って実行する必要のあるプリセットコードが選択されます。では、シェルプロセスがa.outプロセスと異なるのはなぜですか?シェルプロセスの子プロセスもシェルプロセスである必要があるのは当然です。a.outは明らかにシェルとは異なります。ここでそれをどのように理解する必要がありますか?


exec関数ファミリ:

NAME
execl、execlp、execle、execv、execvp、execvpe-ファイルを実行するファイルを実行する!

SYNOPSIS
   #include <unistd.h>

   extern char **environ;

   int execl(const char *path, const char *arg, ...
                   /* (char  *) NULL */);
   int execlp(const char *file, const char *arg, ...
                   /* (char  *) NULL */);
   int execle(const char *path, const char *arg, ...
                   /*, (char *) NULL, char * const envp[] */);
   int execv(const char *path, char *const argv[]);
   int execvp(const char *file, char *const argv[]);
   int execvpe(const char *file, char *const argv[],
                   char *const envp[]);

関数のexec()ファミリは、現在のプロセスイメージを新しいプロセスイメージに置き換えます。

exec関数ファミリは、現在のプロセスイメージを新しいプロセスイメージに
ここに画像の説明を挿入
置き換えます。新しいプロセスを作成するのではなく、プロセスを置き換えるだけです。

戻り値
exec()関数は、エラーが発生した場合にのみ戻ります。戻り値は-1で、エラーを示すためにerrnoが設定されます。

execは、実行が失敗した場合にのみ値を返します。


実験1:execの最初の経験、execとバッファ間の接続はfflush()に注意を払う必要があります

コマンド:date +%s:指定された形式で現在の時刻を取得します

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>


int main(void)
{
	int i,j,mark,n;
	pid_t pid;
	
	puts("Begin!");//puts() 输出时会自动换行

	execl("/bin/date","date","+%s",NULL);
	perror("execl");//如果执行到此 说明 exec替换失败
	exit(1);

	puts("End!\n");
		
	
	exit(0);
}


mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
Begin!
1613136072
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
1613136191
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

結果は期待どおりです。プログラムがexec()に対して実行されると、現在のプロセスが日付プロセスに置き換えられます。

注:コマンドラインで実行可能プログラムを実行すると、Beginが出力されますが、/ tmp / outに再配置した後、Beginは出力されません。

なぜ???

コマンドラインを実行すると、putsが端末、つまりラインバッファである標準出力に出力されるため、印刷開始があります。/ tmp / outに再配置されると、putsは完全にバッファリングされたファイルに出力され、改行文字はバッファを更新しませんが、バッファに格納され、更新する前にexecl()を実行します。つまり、プロセスイメージの日付は置換現在のプロセスイメージとバッファ情報も上書きされます。したがって、次の点に注意する必要があります。

fork()の前にfflush(NULL
)を、execl()の前にfflush(NULL )を使用して
、バッファーフラッシュします。

これは:

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>


int main(void)
{
	int i,j,mark,n;
	pid_t pid;
	
	puts("Begin!");//puts() 输出时会自动换行
fflush(NULL);
	execl("/bin/date","date","+%s",NULL);
	perror("execl");//如果执行到此 说明 exec替换失败
	exit(1);

	puts("End!\n");
		
	
	exit(0);
}



mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
Begin!
1613136824
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

実験1では、新しいプロセスイメージを使用して、自分で作成した現在のプロセスイメージを置き換えることは意味がありません。新しいプロセスを直接使用する方がよいので、execの主なアプリケーションはどこにありますか。

実験2:exec、fork()の意味exec()wait()3つの軸の使用:圧倒的

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>


int main(void)
{
	int i,j,mark,n;
	pid_t pid;
	
	puts("Begin!");

	fflush(NULL);
	pid = fork();
	if(pid < 0)
	{
		perror("fork()");
		exit(1);
	}
	else if(pid == 0) //child  用子进程替换 date
	{
		fflush(NULL);
		execl("/bin/date","date","+%s",NULL);
		perror("execl");
		exit(1);
	}

	wait(NULL);

	puts("End!");
		
	
	exit(0);
}


mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
Begin!
1613137594
End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
Begin!
1613137607
End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

親プロセスは、子プロセスの作成を担当します。子プロセスは作業を担当します。つまり、日付プロセスに置き換えられ、最後に親プロセスは子プロセスリソースの解放を待機します。


シェルプロセスとa.outプロセスの関係についての質問1の説明は次のとおりです。明らかに、シェルプロセスの子プロセスイメージはa.outプロセスイメージに置き換えられました!

おすすめ

転載: blog.csdn.net/LinuxArmbiggod/article/details/113797632