子プロセスは親プロセスのバッファーをコピーできますか?

「UNIXAdvancedEnvironmentProgramming」のプロセス制御セクションには、ほぼ次のような例があり
ます。子プロセスで変数を変更し、親プロセスの後で変数の変更を観察します。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<sys/mman.h>
#include<pthread.h>
#include<semaphore.h>
#include <netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<sys/epoll.h>
#include<unistd.h>
#include<dirent.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<errno.h>
#include<signal.h>
#include<fcntl.h>
#include<sys/wait.h>
int glob=6;
char buf[]="write to stdout\n";
int main(int argc,char**argv)
{
    
    
    int var;
    pid_t pid;
    var =88;
    if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1){
    
    
        fprintf(stderr,"write error");
        exit(0);
    }
    printf("before fork\n");
    // fflush(stdout);
    // setbuf(stdout,NULL);
    // setvbuf(stdout,(char*)NULL,_IONBF,0);
    if((pid=fork())<0){
    
    
        fprintf(stderr,"fork error");
        exit(0);
    }else if(pid==0){
    
    
        glob++;
        var++;
    }else
        sleep(2);
    printf("pid =%d ,glob =%d ,var=%d\n",getpid(),glob,var);
    return 0;
}

最初は、子プロセスが書き込み時に親プロセスのスタックとデータスペースをコピーし、子プロセスが親プロセスの変数を変更するため、これも当てはまると思いました。
しかし、本は突然振り返り、標準のIO関数書き込みバッファーをコピーする問題について言及しました。

問題は次のとおりです。書き込み(STDOUT_FILENO)が端末に1回出力され、printf( "フォークの前\ n")が端末に1回印刷されます。しかし、この結果をリダイレクトa.out >a.txtの形式で
ファイルにリダイレクトすると、これらのステートメントは数回出力されますか?
回答:write(STDOUT_FILENO)は1回出力され、printf( "before fork \ n")は2回出力され
ます。どうした?この本は、writeにはキャッシュがなく、printfには8192バイトのキャッシュがあると指摘しています。驚くべきことであり、見落とされがちなのは、子プロセスが親プロセスの書き込みバッファーの内容を継承することですでは、なぜこの文を端末に書き込んだときに
出力されなかったのに、ファイルに書き込んだときに表示されたのでしょうか。これは、標準出力が行バッファーであるためです。行バッファーを更新するために書き込んだコンテンツには、「\ n」の新しい行文字があります。したがって、プロセスはこのコンテンツを取得できません。ただし、リダイレクトは出力ポイントをファイルに設定することであり、この時点で、そのバッファリングモードは、通常のファイルを書き込むためのバッファリングモードになります。フルバッファリング(「UNIX高度な環境プログラミング」の第5章を理解していません)これにより、親プロセスのprintfが終了した後、バッファ内のバッファのコンテンツが作成され、コンテンツが子プロセスにコピーされます。子プロセスもこの文を印刷します。

好奇心旺盛な赤ちゃんは、どうして子供がこの文を印刷できないのかと尋ねます。
答えは、これら3つの関数のいずれかを使用して、親プロセスprintfの後にバッファーを更新することです。

     fflush(stdout);
     setbuf(stdout,NULL);
    setvbuf(stdout,(char*)NULL,_IONBF,0);

また、書き込みバッファが8192バイトであることがわかります。8192バイトを超えて書き込む場合、バッファはフラッシュされていますか?
答えはイエスです。

次の実験:文字列が300バイトになるまで、printf( "forkの前\ n")に多くのスペースを追加します。次に、3000×30 = 9000 = 8192の30回印刷します。これは、このフルバッファーの下で、300×28 = 8400バイトの印刷後に、バッファーのすべての内容がフラッシュされることを意味します。ファイルに文の文字列を印刷できますか?親プロセスの30+は、バッファー(30-28)= 32の子プロセスに引き続き継承されます。答えは確かにそうです。

このとき、このコマンドを使用して、a.out |grep before | wc
表示できる行数推測しますか?32です!ここ|では、標準出力をgrepの実行可能ファイルにリダイレクトします。この記事をこれまで読んだことがない場合は、30になると思っていたはずです。びっくり?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<sys/mman.h>
#include<pthread.h>
#include<semaphore.h>
#include <netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<sys/epoll.h>
#include<unistd.h>
#include<dirent.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<errno.h>
#include<signal.h>
#include<fcntl.h>
#include<sys/wait.h>
int glob=6;
char buf[]="write to stdout\n";
int main(int argc,char**argv)
{
    
    
    int var;
    pid_t pid;
    var =88;
    if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1){
    
    
        fprintf(stderr,"write error");
        exit(0);
    }
for(int i=0;i<30;i++)
    printf("before fork                                                                                                                                                                                                                                                                                               \n");

    // fflush(stdout);
    // setbuf(stdout,NULL);
    // setvbuf(stdout,(char*)NULL,_IONBF,0);
    if((pid=fork())<0){
    
    
        fprintf(stderr,"fork error");
        exit(0);
    }else if(pid==0){
    
    
        glob++;
        var++;
    }else
        sleep(2);
    printf("pid =%d ,glob =%d ,var=%d\n",getpid(),glob,var);
    return 0;
}

それを発見したので、自分で小さな実験をすることで多くを得ることができます。

おすすめ

転載: blog.csdn.net/adlatereturn/article/details/105691795