我正在使用 Exec 系列函式以 C 語言模擬 bash 命令。
這只是更大專案的部分代碼。為了簡單起見,現在大多數東西都是硬編碼的,但是將來我需要使用管道或重定向運算子執行任何 bash 命令,這就是代碼處于回圈狀態的原因。我知道我可以使用單個檔案描述符(沒有二維陣列)來實作當前示例的結果,但我需要概括多個 |、> 命令的代碼。我無法洗掉回圈。
即使正確關閉所有描述符后,我也會收到錯誤的描述符錯誤。找不到原因。
int main()
{
int numOfCmds = 2;
int numOfPipes = numOfCmds -1;
int pipes[numOfPipes][2];
for(int i=0;i<numOfPipes;i )
if(pipe(pipes[i])<0) return 1;
for(int i=0;i<numOfCmds;i )
{
int child = fork();
if(child == 0)
{
if(i==0)
{
for(int i=0;i<numOfPipes;i )
{
close(pipes[i][0]);
}
printf("hey\n");
dup2(pipes[i][1], STDOUT_FILENO);
close(pipes[i][1]);
char *cmd1_args[3] = {"ls", "-l", NULL};
execvp(cmd1_args[0], cmd1_args);
}
if(i==1)
{
for(int i=0;i<numOfPipes;i )
{
close(pipes[i][1]);
}
printf("bye\n");
dup2(pipes[i][0], STDIN_FILENO);
close(pipes[i][0]);
char *cmd2_args[3] = {"wc", "-l", NULL};
execvp(cmd2_args[0], cmd2_args);
}
return 0;
}
}
for(int i=0;i<numOfCmds;i )
{
for(int j=0;i<2;j )
close(pipes[i][j]);
}
for(int i=0;i<numOfCmds;i ) wait(NULL);
return 0;
錯誤:
嘿再見 wc:'標準輸入':錯誤的檔案描述符 0 wc:-:錯誤的檔案描述符分段錯誤(核心轉儲)
uj5u.com熱心網友回復:
您的問題是您正在重用(嵌套)i. 使用-WshadowGCC 的選項來避免這樣做。并且 的值i有時會超出檔案描述符對陣列的末尾,這會導致混亂(未定義的行為)。
你有:
for(int i=0;i<numOfCmds;i )
{
int child = fork();
if(child == 0)
{
if(i==0)
{
for(int i=0;i<numOfPipes;i )
{
close(pipes[i][0]);
}
printf("hey\n");
dup2(pipes[i][1], STDOUT_FILENO);
close(pipes[i][1]);
char *cmd1_args[3] = {"ls", "-l", NULL};
execvp(cmd1_args[0], cmd1_args);
}
if(i==1)
{
for(int i=0;i<numOfPipes;i )
{
close(pipes[i][1]);
}
printf("bye\n");
dup2(pipes[i][0], STDIN_FILENO);
close(pipes[i][0]);
char *cmd2_args[3] = {"wc", "-l", NULL};
execvp(cmd2_args[0], cmd2_args);
}
return 0;
}
}
您的(外部)回圈控制變數是i;i然后你有一個由關閉一些管道的不同控制的內部回圈。我使用的 GCC 報告您pipes[i][0]在dup2()呼叫wc.
您需要重新使用i(使用一些不同的名稱 -j并且k(對于“孩子”?)是可用的)。并仔細檢查您正在關閉的檔案管道描述符。
您的父母回圈關閉檔案描述符是:
for(int i=0;i<numOfCmds;i )
{
for(int j=0;i<2;j )
close(pipes[i][j]);
}
你需要使用numOfPipes而不是numOfCmds,你需要你的內部回圈來測驗j,而不是i。
這是一些有效的大量檢測代碼。但修復不是很普遍:
/* SO 7165-1018 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int numOfCmds = 2;
int numOfPipes = numOfCmds - 1;
int pipes[numOfPipes][2];
for(int i=0;i<numOfPipes;i )
if(pipe(pipes[i])<0) return 1;
for (int i = 0; i < numOfPipes; i )
printf("%d: pipe[%d][0] = %d; pipe[%d][1] = %d\n",
getpid(), i, pipes[i][0], i, pipes[i][1]);
for(int i=0;i<numOfCmds;i )
{
int child = fork();
printf("%d: child = %d\n", getpid(), child);
if(child == 0)
{
if(i==0)
{
for(int i=0;i<numOfPipes;i )
{
printf("%d: ls: close %d\n", getpid(), pipes[i][0]);
close(pipes[i][0]);
}
printf("%d: hey\n", getpid());
dup2(pipes[i][1], STDOUT_FILENO);
printf("%d: ls: close %d\n", getpid(), pipes[i][1]);
close(pipes[i][1]);
char *cmd1_args[3] = {"ls", "-l", NULL};
execvp(cmd1_args[0], cmd1_args);
fprintf(stderr, "failed to execute %s\n", cmd1_args[0]);
exit(EXIT_FAILURE);
}
if(i==1)
{
for(int i=0;i<numOfPipes;i )
{
printf("%d: wc: close %d\n", getpid(), pipes[i][1]);
close(pipes[i][1]);
}
printf("%d: bye\n", getpid());
dup2(pipes[0][0], STDIN_FILENO);
printf("%d: wc: close %d\n", getpid(), pipes[0][0]);
close(pipes[0][0]);
char *cmd2_args[3] = {"wc", "-l", NULL};
execvp(cmd2_args[0], cmd2_args);
fprintf(stderr, "failed to execute %s\n", cmd2_args[0]);
exit(EXIT_FAILURE);
}
return 0;
}
}
for(int i=0;i<numOfPipes;i )
{
for(int j=0;j<2;j )
{
printf("parent (%d): close %d\n", getpid(), pipes[i][j]);
close(pipes[i][j]);
}
}
for(int i=0;i<numOfCmds;i )
{
int corpse;
int status;
if ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
}
return 0;
}
一個樣本運行(程式sh83,編譯自sh83.c)產生:
42654: pipe[0][0] = 3; pipe[0][1] = 4
42654: child = 42655
42655: child = 0
42655: ls: close 3
42654: child = 42656
parent (42654): close 3
parent (42654): close 4
42655: hey
42656: child = 0
42656: wc: close 4
42656: bye
42656: wc: close 3
128
42654: child 42655 exited with status 0x0000
42654: child 42656 exited with status 0x0000
如果您正在使用多個行程,我發現為大多數訊息添加一個 PID 前綴非常有幫助 - 如輸出所示。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/451655.html
