2016-10-21 4 views
0

私は親パイプと子プロセスの間にパイプを2つ作成します.4096バイトのチャンクでファイルを読み込む必要があります小さい場合は小さく)、パイプを介して読み取られたデータの量と何回読み取られたのかを送信する必要があります。たとえば、6KB ファイルをコピーするには、親はファイルの最初の4KBデータを共有メモリに書き込み、2つの整数1と4096をパイプ経由で子に送信します。子はこれらの2つの数値を受け取り、共有メモリから出力ファイルに4096バイトをコピーし、もう一方のパイプを介して親に1を返します。 1を受信した後、 は、親が左の2KBデータを共有メモリにコピーし、2と2048を子に送信します。子はパイプからそれらを受け取り、2048バイトを出力ファイルにコピーし、親に2で応答します。次に、親は0に0を送る。子は0を受け取り、0で応答してから終了します。親の は0を受け取って終了します。Cパイプを使用して共有メモリを使用してファイルに書き込むためにデータを転送する

#include <sys/types.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 
#include <sys/wait.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 

#define SIZE 4096 
#define NUM_OF_PIPES 2 
#define P_READ 0 
#define P_WRITE 1 
#define C_READ 2 
#define C_WRITE 3 

int main(int argv, char *argc[]) { 


    /*Check if program is called correctly*/ 
    if(argv != 3) { 
    printf("Please call program appropriately\n"); 
    exit(EXIT_FAILURE); 
    } 

    FILE *r, *w, *check; 
    void *sharedMem; 
    int pipes[4]; 
    int shm; 
    char userInput[5]; 
    char *name = "dm11ad_cop4610"; 
    int inChild = 0; 
    int inParent = 0; 
    r = fopen(argc[1], "rb"); 
    check = fopen(argc[2], "rb"); 

    /*Check if read file can open*/ 
    if(r == NULL) { 
    perror("Error opening read file"); 
    exit(EXIT_FAILURE); 
    } 
    /*Check if write file can open*/ 
    if(check == NULL) { 
    perror("Error with write file"); 
    exit(EXIT_FAILURE); 
    } 
    else { 
    fseek(check, 0, SEEK_END); 
    int writeLen = ftell(check); 
    if(writeLen > 0) { 
     rewind(check); 
     printf("Would you like to overwrite file (yes/no): "); 
     scanf("%s", userInput); 
     if(!strcmp(userInput, "yes")) { 
     printf("Overwriting file...\n"); 
     w = fopen(argc[2], "wb"); 
     } 
     else if(!strcmp(userInput, "no")) { 
     printf("Will not overwrite\n"); 
     exit(EXIT_FAILURE); 
     } 
     else { 
     printf("User input not accepted\n"); 
     exit(EXIT_FAILURE); 
     } 
    } 
    } 

    for (int i = 0; i < NUM_OF_PIPES; i++) { 
    if (pipe(pipes+(i*2)) < 0) { 
     perror("Pipe"); 
     exit(EXIT_FAILURE); 
    } 
    } 

    /*Check if forking process is successful*/ 
    pid_t pid = fork(); 
    if(pid < 0) { 
    perror("Fork"); 
    exit(EXIT_FAILURE); 
    } 

    shm = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 
    if(shm == -1) { 
    perror("Shared memory"); 
    exit(EXIT_FAILURE); 
    } 
    if(ftruncate(shm, SIZE) == -1) { 
    perror("Shared Memory"); 
    exit(EXIT_FAILURE); 
    } 

    sharedMem = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0); 
    if(sharedMem == MAP_FAILED) { 
    perror("Mapping shared memory"); 
    exit(EXIT_FAILURE); 
    } 

    if(pid == 0) { 
    while(inParent); 
    inChild = 1; 
    printf("I am in child\n"); 
    close(pipes[P_READ]); 
    close(pipes[P_WRITE]); 
    printf("Closed P pipes\n"); 
    int cBytes, len; 
    printf("Im stuck\n"); 
    len = read(pipes[C_READ], &cBytes, sizeof(cBytes)); 
    printf("There are %i bytes\n", len); 
    if(len < 0) { 
     perror("Failed to read from pipe"); 
     exit(EXIT_FAILURE); 
    } 
    else if(len == 0) { 
     printf("End of fle reached\n"); 
    } 
    else { 
     printf("Writing to file\n"); 
     fwrite(sharedMem, 1, sizeof(sharedMem), w); 
     } 

    printf("Closing C pipes\n"); 
    close(pipes[C_READ]); 
    close(pipes[C_WRITE]); 
    printf("Exiting Child\n"); 
    inChild = 0; 
    } 
    else { 
    while(inChild); 
    inParent = 1; 
    close(pipes[C_READ]); 
    close(pipes[C_WRITE]); 
    int pBytes; 

    int P2SHM = fread(sharedMem, 1, SIZE, r); 
    if(P2SHM < 0) { 
    perror("Could not store to shared memory"); 
    exit(EXIT_FAILURE); 
    } 

    if(write(pipes[P_WRITE], &P2SHM, sizeof(int)) < 0) { 
    perror("Failed to write to pipe"); 
    exit(EXIT_FAILURE); 
    } 

    int C2P = read(pipes[P_READ], &pBytes, sizeof(int)); 
    if(C2P < 0) { 
    perror("Failed to read value from pipe"); 
    exit(EXIT_FAILURE); 
    } 
    else if(C2P == 0) { 
    printf("End of file reached\n"); 
    } 
    else { 
    printf("Received succesfully\n"); 
    } 

    close(pipes[P_READ]); 
    close(pipes[P_WRITE]); 
    inParent = 0; 
    printf("Waiting for child\n"); 
    wait(NULL); 
    } 
    return 0; 
} 

printfsは、プログラムの実行中の場所を確認するのに役立ちます。

len = read(pipes[C_READ], &cBytes, sizeof(cBytes)); 

これはそう答えとしてコードを投稿しないでくださいではなく、私は私が間違っているのかを理解HEPください、割り当てのある時にそれは子プロセスで立ち往生、それはそうです。おかげ

答えて

1

子と親の間の同期メカニズムが疑わしい:inChildinParentため

while(inParent); 
inChild = 1; 

while(inChild); 
inParent = 1; 

初期値が0です。子プロセスが作成された後、各プロセスには可変値のコピーがあります。 inChild = 1inParent = 1を変更すると、現在のプロセス内でのみ変更されます。他のプロセスは新しい値を認識せず、入出力を待つことができません。

これを修正するには、より良い同期アルゴリズムを使用する必要があります。セマフォを処理します。詳細は"5.2 Processes Semaphores"をお読みください。これは、子プロセスで立ち往生

+0

これは疑わしく見えますが、実際は効果がありません。しかし、コードは実際にはそれに全く依存しません。同期を提供するのはパイプ上のI/Oです(とにかくやりたいことです)。 –

+0

@JohnBollingerそう、パイプの同期化されたIOは同期を与えますが、コードで見ることができるように、作成者が期待するものではありません。 – Nikita

+0

私は、OPに間違った期待があるように見えることに同意しますが、これはOPが尋ねたプログラム違反とは関係ありません。 –

1

、それは

len = read(pipes[C_READ], &cBytes, sizeof(cBytes)); 

中にいるようだまあ、はい、私はそれがない想像してみてください。

パイプエンドファイル記述子のために単一の4要素配列を設定するのはちょっと賢明だったと思います。それは本質的に間違っているわけではありませんが、少しばかり進んでいることをあいまいにする傾向があります。

パイプがあなたのためにやるべきことを考えてみましょう。一つのプロセスはパイプの書き込み側に書き込み、もう一方は同じパイプの読み込み側から書き込まれたものを読み込みます。各プロセスが読み書きしているファイルディスクリプタを注意深く見てください。

+0

これで、パイプの端が適切に再定義されました。今、ファイルに書き込むときには、少量のファイルしか書き込まれません。これは私の fwrite(sharedMem、1、sizeof(sharedMem)、w) と関係がありますが、わかりません。 – David

+1

@David、それは別の質問ですが、あなたは問題の場所を特定したようです。 'sharedMem'は' void * 'なので、' sizeof(sharedMem) 'はポインタが指すオブジェクトの大きさとは無関係な' void * 'の大きさを評価します。おそらく4バイトか8バイトのいずれかです。そのように割り当てられたオブジェクトのサイズを測定することはできません。実際には、動的に割り当てられたオブジェクトのサイズを測定することはできません。 –

関連する問題