如何根据特定订单生成三个子进程?

时间:2015-04-17 00:03:40

标签: c message-queue child-process

我被指派创建一个程序来创建三个子进程,如下所示:A,B和C.

  • 进程A从文件中读取数据,并将4KB长的片段发送到消息队列。
  • 进程B从队列中读取这些片段,转换它们并写入 队列中的新数据。
  • 最后,进程C从消息队列中读取转换后的字符串,并将其写入另一个文件。

我使用fork()函数创建它们,并且我无法按顺序生成三个子进程。当我运行程序时,通常在A之前创建进程B或C,并且它们无法从消息队列中正确读取,因为进程A尚未生成。

我怎么能解决这个问题?


这是我一直在努力的代码:

(注意:在运行程序之前必须添加两个参数: ./ program.exe source.txt destination.txt )< / p>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <unistd.h>

#define TAM 4096
#define FILEKEY "/bin/cat"
#define KEY 4242
#define N_PROCESSES 3

typedef struct msgbuf{
    long type;
    char text[TAM];
}message;

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

key_t key;
pid_t pid;
int msqid;
message env, enda, endb;
message rcv;
message conv;
message msg;
int buf_length;
FILE *f1=NULL;
FILE *f2=NULL;
char string[TAM], *receive;
int rc;
int i;
int status;
int p;

if(argc < 2){
    printf("Incorrect command line arguments");
    exit(-1);
}

p = getpid();

/*Opens files*/
f1 = fopen(argv[1], "r");
if(f1 == NULL){
    exit(-1);
}

f2 = fopen(argv[2], "w");
if(f2 == NULL){
    fclose(f1);
    exit(-1);
}

/*Obtains key for message queue*/
key = ftok(FILEKEY, KEY);
if(key == -1){
    fclose(f1);
    fclose(f2);
    exit(-1);
}

/*Creates message queue*/
msqid = msgget(key, IPC_CREAT | 0600);
if(msqid == -1){
    fclose(f1);
    fclose(f2);
    exit(-1);
}

/*Message types*/
env.type = 1; /*Message from process A to process B*/
enda.type = 2; /*Process A has finished reading data from f1*/
conv.type = 3; /*Message from process B to process C*/
endb.type = 4; /*Process B has finished converting the string*/

/*Message size (4KB)*/
buf_length = sizeof(message)-sizeof(long);

/*Creates processes A, B and C*/
for ( i = 0; i < N_PROCESSES; i++){
    pid = fork();
    if(pid == -1){ /*Error*/
        msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
        fclose(f1);
        fclose(f2);
        exit(-1);
    }else if (pid == 0 && i == 0){/*Process A*/

        /*Reads from f1 while end of file is not reached*/
        while (fgets(string, TAM, f1) !=NULL){

            /*Copies string to env.text*/
            strcpy(env.text, cadena);

            /*Sends text fragments (4KB) to message queue*/
            if(msgsnd(msqid, &env, buf_length, IPC_NOWAIT)<0){
                msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
                fclose(f1);
                fclose(f2);
                exit(-1);
            }

        }
        /*Process A sends this message when there's no more data to read*/
        if(msgsnd(msqid, &enda, buf_length, IPC_NOWAIT)<0){
            msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
            fclose(f1);
            fclose(f2);
            exit(-1);
        }
        exit(EXIT_SUCCESS);

    }else if(pid == 0 && i == 1){/*Process B*/

        /*Reads text fragments (4KB) from message queue*/
        while (msgrcv(msqid, &rcv, buf_length, 1, IPC_NOWAIT)>0) {
            /*Converts string*/
            strcpy(receive, rcv.text);

            for(i = 0; i < TAM; i++){
                receive[i] = toupper(receive[i]);
            }

            strcpy(conv.text, receive);

            /*Sends fragments of converted string to message queue*/
            if(msgsnd(msqid, &conv, buf_length, IPC_NOWAIT)<0){
                msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
                fclose(f1);
                fclose(f2);
                exit(-1);
            }
        }
        /*The loop finishes when there's an error or when there are no more type 1 messages to read*/
        /*Reads type 2 message from process A*/
        rc = msgrcv(msqid, &rcv, buf_length, 2, 0);
        if( rc == -1){
            msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
            fclose(f1);
            fclose(f2);
            exit(-1);
        }
        /*Process B sends this message indicating that it has finished sending string fragments*/
        if(msgsnd(msqid, &endb, buf_length, IPC_NOWAIT)<0){
            msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
            fclose(f1);
            fclose(f2);
            exit(-1);
        }
        exit(EXIT_SUCCESS);

    }else if(pid == 0 && i == 2){/*Process C*/

        /*Reads converted string fragments from message queue*/
        while (msgrcv(msqid, &msg, buf_length, 3, IPC_NOWAIT)>0) {
        /*Writes fragments on another file*/
            if(fputs(msg.text, f2)<0){
                exit(-1);
            }

        }
        /*The loop finishes when there are no more fragments to write on f2*/
        /*Then process C reads the last message sent from B*/
        rc = msgrcv(msqid, &rcv, buf_length, 4, 0);
        if( rc == -1){
            msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
            fclose(f1);
            fclose(f2);
            exit(-1);
        }
        exit (EXIT_SUCCESS);
    }

}

/*Parent process waits for processes A, B and C*/
for (i=0; i<N_PROCESSES; i++) {
    pid=wait(&status);
    printf("Process %d with PPID = %d terminated\n", pid, p);
}
msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
fclose(f1);
fclose(f2);
return (EXIT_SUCCESS);
}

1 个答案:

答案 0 :(得分:1)

按照您指定的顺序创建流程,但调度程序可以按照自己喜欢的顺序安排流程,因此您可以在流程A完成之前找到流程B中执行的代码,等等。

我要做的就是设置你想要的情况有2个队列,一个从A到B,另一个从B到C.我在父母那里创建它们以保存东西简单。

然后我让阅读孩子做阻塞读取(没有IPC_NOWAIT的msgrcv()),或者我循环直到我收到故障而不是没有收到数据。

发送过程(A和B)都会放置&#34;以及所有&#34;完成后,指标进入队列,所以接收者会知道他们拥有一切。