直到程序完成,读写文件才算完成

时间:2018-10-21 22:50:49

标签: c

我的程序正在做的是,它需要3个命令,例如wc md5sum等,这些命令在Linux上的文件上运行。它还将文件路径名也作为输入。它为每个命令创建派生,然后将命令输出存储到文件中。完成所有这些操作后,我在main中打印命令输出和结果时间等。

我遇到的问题是,在大文件上运行诸如wc之类的命令需要更长的时间,直到程序完全完成后,命令输出才会保存到文件中。因此,它不会在我的结果中打印出来。

我不确定为什么会这样,因为在子进程完成之前,父进程应打印结果。我需要一些帮助或正确方向的帮助。我宁愿仅将命令输出存储在char *中,而不是写入文件,但我不知道如何将输出重定向到char缓冲区以返回。预先感谢。

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

#define MAXIN 255
#define SEP "--------------------------------------------------------------------------------"

int currProc = 0;
const char *procStrFin[] = {"First process finished...", "Second process finished...", "Third process finished..."};
int p1file = 0;
int p2file = 0;
int p3file = 0;

struct Response
{
  int pid1;
  int pid2;
  int pid3;
  char *result1;
  char *result2;
  char *result3;
  double time1;
  double time2;
  double time3;
};

//Fork and run command with args
struct Response runCmd(char *command1, char *command2, char *command3, char *file)
{
  struct Response res;
  res.result1 = "";
  res.result2 = "";
  res.result3 = "";

  /*
    Command 1 Parse
    */
  char *fullCommand1 = strcat(command1, " ");
  fullCommand1 = strcat(fullCommand1, file);
  //Create an array of split commands for arg1 of execvp
  char *p1s = strtok(fullCommand1, " ");     //start token pointer
  char *splitCommand1[strlen(fullCommand1)]; //init split command array based on size of full command
  int i1 = 0;                                //init counter
  while (p1s != NULL)                        //Loop through each word and store in array
  {
    splitCommand1[i1++] = p1s;
    p1s = strtok(NULL, " ");
  }
  splitCommand1[i1] = NULL; //NULL terminate array

  /*
    Command 2 Parse
    */
  char *fullCommand2 = strcat(command2, " ");
  fullCommand2 = strcat(fullCommand2, file);
  //Create an array of split commands for arg1 of execvp
  char *p2s = strtok(fullCommand2, " ");     //start token pointer
  char *splitCommand2[strlen(fullCommand2)]; //init split command array based on size of full command
  int i2 = 0;                                //init counter
  while (p2s != NULL)                        //Loop through each word and store in array
  {
    splitCommand2[i2++] = p2s;
    p2s = strtok(NULL, " ");
  }
  splitCommand2[i2] = NULL; //NULL terminate array

  /*
    Command 3 Parse
    */
  char *fullCommand3 = strcat(command3, " ");
  fullCommand3 = strcat(fullCommand3, file);
  //Create an array of split commands for arg1 of execvp
  char *p3s = strtok(fullCommand3, " ");     //start token pointer
  char *splitCommand3[strlen(fullCommand3)]; //init split command array based on size of full command
  int i3 = 0;                                //init counter
  while (p3s != NULL)                        //Loop through each word and store in array
  {
    splitCommand3[i3++] = p3s;
    p3s = strtok(NULL, " ");
  }
  splitCommand3[i3] = NULL; //NULL terminate array

  /*
    FORKS
    */
  double time_spent1 = 0.0;
  double time_spent2 = 0.0;
  double time_spent3 = 0.0;
  clock_t begin = clock();
  clock_t end;

  int p1 = fork();
  if (p1 < 0)
  {
    //Output redirect to file and run command
    close(STDOUT_FILENO);
    p1file = open("p1.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
    printf("CMD1:[SHELL 1] STATUS CODE=-1");
  }
  else if (p1 == 0) //P1 Controlled
  {
    //Output redirect to file and run command
    close(STDOUT_FILENO);
    p1file = open("p1.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
    execvp(splitCommand1[0], splitCommand1);
  }
  else //Parent Controlled
  {
    end = clock();
    time_spent1 += (double)(end - begin) / CLOCKS_PER_SEC;
    printf("%s\n", procStrFin[currProc]);
    res.pid1 = p1;
    res.time1 = time_spent1;
    currProc++;
    int p2 = fork();
    if (p2 < 0)
    {
      //Output redirect to file and run command
      close(STDOUT_FILENO);
      p2file = open("p2.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
      printf("CMD2:[SHELL 2] STATUS CODE=-1");
    }
    else if (p2 == 0) //P2 Controlled
    {
      close(STDOUT_FILENO);
      p2file = open("p2.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
      execvp(splitCommand2[0], splitCommand2);
    }
    else //Parent Controlled
    {
      end = clock();
      time_spent2 += (double)(end - begin) / CLOCKS_PER_SEC;
      printf("%s\n", procStrFin[currProc]);
      res.pid2 = p2;
      res.time2 = time_spent2;
      currProc++;
      int p3 = fork();
      if (p3 < 0)
      {
        //Output redirect to file and run command
        close(STDOUT_FILENO);
        p3file = open("p3.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
        printf("CMD3:[SHELL 3] STATUS CODE=-1");
      }
      else if (p3 == 0) //P3 Controlled
      {
        close(STDOUT_FILENO);
        p3file = open("p3.temp", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
        execvp(splitCommand3[0], splitCommand3);
      }
      else //Parent Controlled
      {
        end = clock();
        time_spent3 += (double)(end - begin) / CLOCKS_PER_SEC;
        printf("%s\n", procStrFin[currProc]);
        res.pid3 = p3;
        res.time3 = time_spent3;
        int parent = wait(NULL); //Wait on children
        return res;
      }
    }
  }
}

//Quick max function
float max(float num1, float num2)
{
  return (num1 > num2) ? num1 : num2;
}

/* Take file path and read from file*/
char *readFromFile(char *filename)
{
  char *buffer = 0;
  long length;
  FILE *f = fopen(filename, "rb"); //was "rb"

  if (f)
  {
    fseek(f, 0, SEEK_END);
    length = ftell(f);
    fseek(f, 0, SEEK_SET);
    buffer = (char *)malloc((length + 1) * sizeof(char));
    if (buffer)
    {
      fread(buffer, sizeof(char), length, f);
    }
    fclose(f);
  }
  buffer[length] = '\0';
  // for (int i = 0; i < length; i++) {
  //     printf("buffer[%d] == %c\n", i, buffer[i]);
  // }
  //printf("buffer = %s\n", buffer);

  return buffer;
}

//Deletes file
int deleteFile(char *filename)
{
  if (remove(filename) == 0)
  {
    return 0;
  }
  else
  {
    return 1;
  }
}

//MAIN
int main(int argc, char const *argv[])
{
  char buf[MAXIN];
  //Command 1
  printf("Welcome to MASH!\nmash-1>");
  fgets(buf, MAXIN, stdin);
  buf[strcspn(buf, "\n")] = 0; //remove newlines
  char *cmd1 = strdup(buf);

  //Command 2
  printf("mash-2>");
  fgets(buf, MAXIN, stdin);
  buf[strcspn(buf, "\n")] = 0; //remove newlines
  char *cmd2 = strdup(buf);

  //Command 3
  printf("mash-3>");
  fgets(buf, MAXIN, stdin);
  buf[strcspn(buf, "\n")] = 0; //remove newlines
  char *cmd3 = strdup(buf);

  // File Command
  printf("file>");
  fgets(buf, MAXIN, stdin);
  buf[strcspn(buf, "\n")] = 0; //remove newlines
  char *fileCmd = strdup(buf);

  struct Response response = runCmd(cmd1, cmd2, cmd3, fileCmd);

  //Command Results Output
  int pre = 12;
  int cmd1Len = 80 - (strlen(cmd1) + pre);
  int cmd2Len = 80 - (strlen(cmd2) + pre);
  int cmd3Len = 80 - (strlen(cmd3) + pre);
  char cmd1Sep[80] = "";
  for (int i = 0; i < cmd1Len; i++)
  {
    strcat(cmd1Sep, "-");
  }
  char cmd2Sep[80] = "";
  for (int i = 0; i < cmd2Len; i++)
  {
    strcat(cmd2Sep, "-");
  }
  char cmd3Sep[80] = "";
  for (int i = 0; i < cmd3Len; i++)
  {
    strcat(cmd3Sep, "-");
  }

  //Get file input
  char *cmd1Out = readFromFile("p1.temp");
  char *cmd2Out = readFromFile("p2.temp");
  char *cmd3Out = readFromFile("p3.temp");

  printf("-----CMD 1: %s%s\n", cmd1, cmd1Sep);
  printf("%sResult took:%fms\n", cmd1Out, response.time1);
  printf("-----CMD 2: %s%s\n", cmd2, cmd2Sep);
  printf("%sResult took:%fms\n", cmd2Out, response.time2);
  printf("-----CMD 3: %s%s\n", cmd3, cmd3Sep);
  printf("%sResult took:%fms\n", cmd3Out, response.time3);
  printf("%s\n", SEP);
  printf("Parent PID: %d\n", getpid());
  printf("Children process IDs: %d %d %d.\n", response.pid1, response.pid2, response.pid3);
  printf("Total elapsed time:%fms\n", max(response.time3, max(response.time2, response.time1)));

  //Delete Files
  // deleteFile("p1.temp");
  // deleteFile("p2.temp");
  // deleteFile("p3.temp");
  return 0;
}

示例输出:

Welcome to MASH!
mash-1>wc
mash-2>md5sum
mash-3>grep -c the
file>big.log
First process finished...
Second process finished...
Third process finished...
-----CMD 1: wc------------------------------------------------------------------
Result took:0.000070ms
-----CMD 2: md5sum--------------------------------------------------------------
Result took:0.000120ms
-----CMD 3: grep----------------------------------------------------------------
40
Result took:0.000160ms
--------------------------------------------------------------------------------
Parent PID: 7664
Children process IDs: 7665 7666 7667.
Total elapsed time:0.000160ms

2 个答案:

答案 0 :(得分:0)

在手册页中:

  

wait()系统调用将暂停执行调用过程,直到一个子级终止。

您需要将import wx, threading, math class custom_frame(wx.Frame): def __init__(self, parent, id): self.operators = ['+/-', '0', '.', '=', '1', '2', '3', '+', '4', '5', '6', '-', '7', '8', '9', '*', 'CE', 'C', 'DEL', '/'] self.buttons = [] self.equation = '' wx.Frame.__init__(self, parent, id, 'Calculator', size=(335,505)) self.panel = wx.Panel(self) self.text = wx.StaticText(self.panel, wx.ID_ANY, '0', (0, 0), (100, 20), wx.ALIGN_RIGHT) self.old_text = '' for x in self.operators: button = wx.Button(self.panel, wx.ID_ANY, x) button.Bind(wx.EVT_BUTTON, lambda event, temp=[self, x]: onButtonPress(event, temp) ) self.buttons.append(button) self.threading_Think = threading.Thread(name='Think', target=self.Think) def Think(self): # Run code here, and just repeat its self while True: size = frame.GetSize() maxRows = 4 for k, v in enumerate(self.buttons): currentRow = math.floor(k/4) + 1 buttonSize = (size[0]/maxRows, (size[1]*0.5)*(1/(len(self.operators)/maxRows))) v.SetSize(buttonSize) v.SetPosition( ((k%maxRows)*buttonSize[0], size[1]-(currentRow*buttonSize[1])) ) if self.text.GetLabel() != self.old_text: self.text.SetLabel(self.old_text) self.old_text = self.text.GetLabel() self.text.SetPosition((size[0]-200, 0)) def onButtonPress(event, temp): if temp[1] == '+/-' or temp[1] == 'DEL' or temp[1] == 'CE': pass elif temp[1] == 'C': temp[0].equation = '' elif temp[1] == '=': temp[0].equation = str(eval(temp[0].equation)) else: temp[0].equation = temp[0].equation + temp[1] temp[0].old_text = temp[0].equation print(temp[0].equation) app = wx.App() frame = custom_frame(parent=None, id=-1) frame.SetMinSize((335, 505)) frame.threading_Think.start() frame.Show() app.MainLoop() waitpid一起使用,以作为等待所有子项完成的第一个参数。

答案 1 :(得分:0)

您当前拥有:

int parent = wait(NULL); //Wait on children

这将等待一个孩子,而不是所有孩子。在这方面,shell wait命令与wait()系统调用不同。

因此,您需要类似:

int corpse;
int status;
while ((corpse = wait(&status)) > 0)
    printf("PID %d exited with status 0x%.4X\n", corpse, status);

这会循环直到不再有孩子。一种可能的替代方法是使用waitpid()依次等待每个孩子,但是……明智地,您需要将孩子的pids存储在数组中,而不是三个数字变量中,但您可以使用三个变量来做到这一点。

您的代码需要使用更多的函数,并且随着变量名称的更改,所有代码的重复次数要少得多三遍。使用当前的代码结构,处理2或4或5个孩子应该和处理3一样简单,这只是微不足道的。

例如,如果您创建了一个函数:

static void wait_for_pid(int pid)
{
    int corpse;
    int status;
    if ((corpse = waitpid(pid, &status, 0)) > 0)
        printf("PID %d exited with status 0x%.4X\n", corpse, status);
    else
    {
        fprintf(stderr, "failed to wait for PID %d\n", pid);
        exit(EXIT_FAILURE);
    }
}

然后您可以使用:

wait_for_pid(res.pid1);
wait_for_pid(res.pid2);
wait_for_pid(res.pid3);

不好,但是比写出waitpid()代码并进行3次错误检查要好。

您的计时码也很可疑。几乎可以保证不会给出正确的结果。您甚至在启动过程3之前就停止了过程2的计时,但这并不意味着过程2甚至可以进行,而要完成得多。