所以我试图并行处理,并使用execv。发生的问题是,当我并行处理时,execv仅在一个子进程中运行,而不能在两个子进程中运行。我知道两个子进程的运行都是由于有关pid的printf语句。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char * argv[]) {
char input[100];
char * path[15];
path[0] = "/bin/";
char str[200];
FILE * fp;
if (argc == 2) {
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("Error! opening file");
// Program exits if file pointer returns NULL.
exit(1);
}
}
do {
if (argc != 2) {
printf("dash> ");
fgets(input, 100, stdin);
} else if (argc == 2) {
if (fgets(input, 100, fp) == NULL)
exit(0);
printf(input);
}
input[strcspn(input, "\n")] = '\0';
char * token = strtok(input, " ");
int c = 0;
if ((strcmp(token, "exit") != 0) && (strcmp(token, "cd") != 0) && (strcmp(token, "path") != 0)) {
do {
if (path[c] == NULL) {
printf("p error");
break;
}
strcpy(str, path[c]);
strcat(str, token);
c++;
} while (access(str, X_OK) == -1);
}
if (strcmp(token, "exit") == 0) {
exit(0);
} else if (strcmp(token, "cd") == 0) {
token = strtok(NULL, " ");
if (chdir(token) == -1)
printf("errorcd");
} else if (strcmp(token, "path") == 0) {
int counter = 0;
while (path[counter] != NULL) {
path[counter] = strtok(NULL, " ");
counter++;
}
} else {
char * myargs[15];
char * par[15];
myargs[0] = token;
int counter = 0;
int track = 0;
int and = 1;
while (myargs[counter] != NULL) // &&(strcmp(myargs[counter],">"))!=0){
{
counter++;
myargs[counter] = strtok(NULL, " ");
}
int a = 0;
int i = 0;
int j = 0;
int t = 0;
// printf(myargs[i]);
for (i = 0; i <= counter - 1; i++) {
if (strcmp(myargs[i], "&") == 0)
and++;
}
int temp = and + 1;
// printf("No. %d",and);
int rc[15];
for (i = 0; i < and; i++) {
a = 0;
for (j = t; j <= counter - 1; j++) {
par[a] = myargs[j];
a++;
if (strcmp(myargs[j], "&") == 0) {
t = j + 1;
break;
}
}
if (and == 0)
par[j + 1] = NULL;
else
par[j] = NULL;
rc[i] = fork();
if (rc[i] < 0) // fork failed
{
printf("Error");
return 0;
} else if (rc[i] == 0) // child process
{
printf("\nhello, I am child (pid:%d)\n", (int) getpid());
if (j > 1) {
if (strcmp(par[j - 2], ">") == 0) {
int fd = open(par[j - 1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
dup2(fd, 1); // make stdout go to file
dup2(fd, 2); // make stderr go to file - you may choose to not do this
// or perhaps send stderr to another file
// }
par[counter - 2] = NULL;
}
}
execv(str, par);
printf("failed");
}
} // parent process
int status;
pid_t pid;
while (temp > 0) {
// waitpid(pid[i], 0, 0);
pid = wait( & status);
printf("Child with PID %ld exited with status 0x%x.\n", (long) pid, status);
--temp; // TODO(pts): Remove pid from the pids array.
}
}
} while (strcmp(input, "exit") != 0);
return 0;
}
我知道这段代码很糟糕,我已经有一段时间没有编码了,有点生疏了。无论如何,这是示例输入和输出。
dash> pwd & ls
hello, I am child (pid:40037)
hello, I am child (pid:40036)
/home/012/a/ax/axh161330/project1
Child with PID 40036 exited with status 0x0.
Child with PID 40037 exited with status 0x8b.
Child with PID -1 exited with status 0x8b.
如您所见,只有一个execv命令被执行(pwd
),而另一个从未发生(ls
)。第一个命令将始终有效,而第二个命令将不会发生。
答案 0 :(得分:0)
至少在pwd & ls
作为命令行时,这种对代码的修改才有效。问题之一是查找命令路径名的循环位置错误。另一个问题是wait()
循环在错误的位置。
另一个问题是命令参数没有正确分开。
代码显示了我添加的打印内容(很多),以确保我了解发生了什么,并且突出了一些问题。
源代码(exec29.c
):
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char input[100];
char *path[15];
path[0] = "/bin/";
FILE *fp;
if (argc == 2)
{
if ((fp = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Error! opening file %s\n", argv[1]);
exit(1);
}
}
do
{
if (argc != 2)
{
printf("dash> ");
if (fgets(input, 100, stdin) == NULL)
exit(0);
}
else if (argc == 2)
{
if (fgets(input, 100, fp) == NULL)
exit(0);
}
input[strcspn(input, "\n")] = '\0';
printf("%s\n", input);
char *token = strtok(input, " ");
int temp = 0;
if (strcmp(token, "exit") == 0)
{
exit(0);
}
else if (strcmp(token, "cd") == 0)
{
token = strtok(NULL, " ");
if (chdir(token) == -1)
fprintf(stderr, "error: cd %s\n", token);
}
else if (strcmp(token, "path") == 0)
{
int counter = 0;
while (path[counter] != NULL)
{
path[counter] = strtok(NULL, " ");
if (path[counter] != NULL)
printf("PATH: %s\n", path[counter]);
counter++;
}
}
else
{
char *myargs[15];
char *par[15];
myargs[0] = token;
int counter = 0;
int n_cmds = 1;
while (myargs[counter] != NULL)
{
counter++;
myargs[counter] = strtok(NULL, " ");
}
for (int i = 0; i < counter; i++)
printf("%d: [[%s]]\n", i, myargs[i]);
for (int i = 0; i < counter; i++)
{
if (strcmp(myargs[i], "&") == 0)
n_cmds++;
}
temp = n_cmds;
printf("Num commands: %d\n", n_cmds);
int t = 0;
for (int i = 0; i < n_cmds; i++)
{
int a = 0;
for (int j = t; j < counter; j++)
{
if (strcmp(myargs[j], "&") == 0)
{
t = j + 1;
break;
}
par[a++] = myargs[j];
}
par[a] = NULL;
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "Error: fork failed\n");
return 1;
}
else if (rc == 0)
{
char str[200];
printf("hello, I am child (pid:%d)\n", (int)getpid());
int c = 0;
do
{
if (path[c] == NULL)
{
fprintf(stderr, "path error - no PATH left\n");
break;
}
strcpy(str, path[c++]);
strcat(str, par[0]);
} while (access(str, X_OK) == -1);
printf("Cmd: [[%s]]\n", str);
char **args = par;
while (*args != NULL)
printf("[[%s]]\n", *args++);
fflush(stdout);
execv(str, par);
fprintf(stderr, "%s: failed\n", str);
exit(1);
}
}
}
while (temp > 0)
{
int status;
pid_t pid = wait(&status);
printf("%d: Child with PID %ld exited with status 0x%.4x.\n",
(int)getpid(), (long)pid, status);
--temp;
}
} while (strcmp(input, "exit") != 0);
return 0;
}
给出文件test-exec
,其中包含:
pwd & ls
pwd -P & ls -l
我得到了示例输出(exec29 test-exec
):
pwd & ls
0: [[pwd]]
1: [[&]]
2: [[ls]]
Num commands: 2
hello, I am child (pid:4247)
Cmd: [[/bin/pwd]]
[[pwd]]
hello, I am child (pid:4248)
Cmd: [[/bin/ls]]
[[ls]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4247 exited with status 0x0000.
exec23.c exec29 exec29.c exec29.dSYM exec97.c makefile test-exec test-exec-2
4246: Child with PID 4248 exited with status 0x0000.
pwd -P & ls -l
0: [[pwd]]
1: [[-P]]
2: [[&]]
3: [[ls]]
4: [[-l]]
Num commands: 2
hello, I am child (pid:4249)
Cmd: [[/bin/pwd]]
[[pwd]]
[[-P]]
hello, I am child (pid:4250)
Cmd: [[/bin/ls]]
[[ls]]
[[-l]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4249 exited with status 0x0000.
total 80
-rw-r--r-- 1 jleffler staff 3722 Sep 10 20:43 exec23.c
-rwxr-xr-x 1 jleffler staff 9644 Sep 10 21:41 exec29
-rw-r--r-- 1 jleffler staff 4054 Sep 10 21:41 exec29.c
drwxr-xr-x 3 jleffler staff 96 Sep 10 21:05 exec29.dSYM
-rw-r--r-- 1 jleffler staff 4549 Sep 10 21:45 exec97.c
-rw-r--r-- 1 jleffler staff 163 Sep 10 21:41 makefile
-rw-r--r-- 1 jleffler staff 24 Sep 10 21:47 test-exec
-rw-r--r-- 1 jleffler staff 34 Sep 10 21:38 test-exec-2
4246: Child with PID 4250 exited with status 0x0000.
我确实删除了与I / O重定向有关的代码;我没有删除与cd
,exit
或path
相关的代码,但我也没有对其进行测试。
一个较小的模糊点:标准标头<iso646.h>
定义了一个宏and
,该宏扩展为&&
。最好不要使用该标头中的任何名称作为变量名,尽管确实很少有人在C中使用标头(但名称在C ++中保留为“替代表示”)。