我正在Windows上模拟循环管道的递归C函数。
到目前为止,这是我的功能:
static BOOL execute_in_pipe(char (*cmdline)[1024], char *env, int index,
int pipe_length, STARTUPINFO *old_suinfo, HANDLE proc_handles[])
{
//Create new startup info
STARTUPINFO suinfo;
memset(&suinfo, 0, sizeof(suinfo));
suinfo.cb = sizeof(suinfo);
//Create new process info
PROCESS_INFORMATION pinfo;
//Make pipe
HANDLE pipe_out_rd, pipe_out_wr;
if(index > 0) {
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (! CreatePipe(&pipe_out_rd, &pipe_out_wr, &sa, 0))
{
CloseHandle(pipe_out_wr);
CloseHandle(pipe_out_rd);
//res.tag = NATIVE_ERR_PIPE_FAILED;
//return res;
}
//Set output of last process to write handle
if((*old_suinfo).hStdInput == 0) {
(*old_suinfo).hStdInput = hIn;
}
(*old_suinfo).hStdOutput = pipe_out_wr;
(*old_suinfo).dwFlags = STARTF_USESTDHANDLES;
//Set input of this process to read handle
suinfo.hStdInput = pipe_out_rd;
if(index >= pipe_length-1) {
suinfo.hStdOutput = hOut;
}
suinfo.dwFlags = STARTF_USESTDHANDLES;
}
BOOL result = TRUE;
if(index < pipe_length-1) {
result = execute_in_pipe(cmdline, env, index+1, pipe_length, &suinfo, proc_handles);
}
//Return whether creating process succeeds
if(!CreateProcess(NULL, cmdline[index], NULL, NULL,
(pipe_length>1), 0, env, NULL, &suinfo, &pinfo))
{
return FALSE;
}
CloseHandle(pinfo.hThread);
proc_handles[index] = pinfo.hProcess;
return result;
}
我制作了两个c程序来测试管道:
seed.c
#include <stdio.h>
int main() {
printf("Hello");
}
append.c
#include <stdio.h>
#include <string.h>
int main() {
char str[200];
scanf( "%s", str );
printf("%s World!", str);
}
然后我使用以下命令调用了这些函数
STARTUPINFO suinfo;
HANDLE proc_handles[2];
printf("Starting\n");
char cmdline[2][1024] = {"seed.exe", "append.exe"};
execute_in_pipe(cmdline, 0, 0, 2, &suinfo, proc_handles);
WaitForMultipleObjects(2, proc_handles, TRUE, INFINITE);
调用此函数时,控制台将打印出“正在启动”,然后永远等待...
我很确定原因是scanf试图读取FULL LINE(最多是某种分隔符)。当我将seed.c更新为`printf(“ Hello \ n”)时,它运行正常。
是的,这只是一条规则吗?所有管道处理都应使用换行符吗?
好吧,在命令提示符中调用seed.exe | append.exe
很有效!即使没有换行符!我的代码丢失了什么?
编辑: 正如某些人所指出的,当所有管道都关闭时,Unix管道会进入“流结束”状态(不是我最初认为的EOF)。在测试Unix管道系统时,不会出现此问题,因此流结束就像分隔符一样。 Windows是否做类似的事情?如果是这样,我是否需要关闭某些内容以使其结束流?
答案 0 :(得分:1)
您应该使用命名管道而不是未命名管道来进行I / O重定向。关闭服务器的管道句柄后,客户端上的scanf()会知道它并停止等待换行符。
下面的代码是用pascal编写的,但并不难理解。
const
BUFSIZE:integer = 512;
Pipename:String = '\\.\pipe\devcpp_run';
InputWrite := CreateNamedPipe(
pAnsiChar(Pipename), // pipe name
PIPE_ACCESS_OUTBOUND, // read/write access
PIPE_TYPE_BYTE or // message type pipe
PIPE_READMODE_BYTE or // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
nil); // default security attribute
if InputWrite = INVALID_HANDLE_VALUE then begin
Exit;
end;
InputRead := CreateFile(
PAnsiChar(Pipename), // pipe name
GENERIC_READ,
0, // no sharing
@sa, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
0);
if InputRead = INVALID_HANDLE_VALUE then begin
Exit;
end;
StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES;
StartupInfo.hStdInput := InputRead;
StartupInfo.hStdOutput := 7; // Undocumented Handle of Console Output
StartupInfo.hStdError := 11; // Undocumented Handle of Console Error Output
end;
答案 1 :(得分:0)
scanf
正在等待“结束”条件并挂起。这就是问题。
以下是一种变通方法,您可以查看是否有帮助:
像这样编辑append.c
:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#define BUFFER_SIZE 200
int main()
{
DWORD dwRead = 0;
char str[BUFFER_SIZE];
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
for (;;)
{
BOOL bSuccess = ReadFile(hStdIn, str, BUFFER_SIZE, &dwRead, NULL);
if (bSuccess && dwRead > 0) break;
}
for(DWORD i = 0; i< dwRead; i++)
printf("%c", str[i]);
printf(" World!");
}
使用ReadFile
而不是scanf
来读取标准输入流。