我的程序正在做的是,它需要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
答案 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甚至可以进行,而要完成得多。