none
请问一个writefile函数卡住的问题 RRS feed

  • 问题

  • 我的目标是从控制台调用一个子进程并重定向输入和输入

    现在的问题是,当我的子进程里本身也重定向输入输出,并且输入文件的长度超过了BUFSIZE后,程序就会运行到writefile函数处卡住,请问这是什么原因,如何避免。

    父进程代码如下,摘抄自http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx,有一些改动

    // redirectInputAndOutput.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #include <windows.h> 
    #include <tchar.h>
    #include <stdio.h> 
    #include <strsafe.h>
    
    #define BUFSIZE 4096 
     
    HANDLE g_hChildStd_IN_Rd = NULL;
    HANDLE g_hChildStd_IN_Wr = NULL;
    HANDLE g_hChildStd_OUT_Rd = NULL;
    HANDLE g_hChildStd_OUT_Wr = NULL;
    
    HANDLE g_hInputFile = NULL;
     
    void CreateChildProcess(void); 
    void WriteToPipe(void); 
    void ReadFromPipe(void); 
    void ErrorExit(PTSTR); 
     
    int _tmain(int argc, TCHAR *argv[]) 
    { 
       SECURITY_ATTRIBUTES saAttr;
    	 TCHAR file[100];
     
       printf("\n->Start of parent execution.\n");
    
    // Set the bInheritHandle flag so pipe handles are inherited. 
     
       saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
       saAttr.bInheritHandle = TRUE; 
       saAttr.lpSecurityDescriptor = NULL; 
    
    // Create a pipe for the child process's STDOUT. 
     
       if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) 
          ErrorExit(TEXT("StdoutRd CreatePipe")); 
    
    // Ensure the read handle to the pipe for STDOUT is not inherited.
    
       if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
          ErrorExit(TEXT("Stdout SetHandleInformation")); 
    
    // Create a pipe for the child process's STDIN. 
     
       if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
          ErrorExit(TEXT("Stdin CreatePipe")); 
    
    // Ensure the write handle to the pipe for STDIN is not inherited. 
     
       if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
          ErrorExit(TEXT("Stdin SetHandleInformation")); 
     
    // Create the child process. 
       
       CreateChildProcess();
    
    // Get a handle to an input file for the parent. 
    // This example assumes a plain text file and uses string output to verify data flow. 
     
    	 wsprintf(file,L"E:\\input.txt");//输入文件长度超过了BUFSIZE时,writefile函数就会卡住
       g_hInputFile = CreateFile(
           file, 
           GENERIC_READ, 
           0, 
           NULL, 
           OPEN_EXISTING, 
           FILE_ATTRIBUTE_READONLY, 
           NULL); 
    
       if ( g_hInputFile == INVALID_HANDLE_VALUE ) 
          ErrorExit(TEXT("CreateFile")); 
     
    // Write to the pipe that is the standard input for a child process. 
    // Data is written to the pipe's buffers, so it is not necessary to wait
    // until the child process is running before writing data.
     
       WriteToPipe(); 
       printf( "\n->Contents of %s written to child STDIN pipe.\n", argv[1]);
     
    // Read from pipe that is the standard output for child process. 
     
       printf( "\n->Contents of child process STDOUT:\n\n", argv[1]);
       ReadFromPipe(); 
    
       printf("\n->End of parent execution.\n");
    
    // The remaining open handles are cleaned up when this process terminates. 
    // To avoid resource leaks in a larger application, close handles explicitly. 
    
       return 0; 
    } 
     
    void CreateChildProcess()
    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
    { 
    		TCHAR szCmdline[100];
    		char temp[100];
    		TCHAR tc[100];
    		sprintf(temp,"e:\\a.exe");
    		MultiByteToWideChar(CP_ACP,0,temp,-1,tc,100);
    		wsprintf(szCmdline,L"%s",tc);
       PROCESS_INFORMATION piProcInfo; 
       STARTUPINFO siStartInfo;
       BOOL bSuccess = FALSE; 
     
    // Set up members of the PROCESS_INFORMATION structure. 
     
       ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
     
    // Set up members of the STARTUPINFO structure. 
    // This structure specifies the STDIN and STDOUT handles for redirection.
     
       ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
       siStartInfo.cb = sizeof(STARTUPINFO); 
       siStartInfo.hStdError = g_hChildStd_OUT_Wr;
       siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
       siStartInfo.hStdInput = g_hChildStd_IN_Rd;
       siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
     
    // Create the child process. 
        
       bSuccess = CreateProcess(NULL, 
          szCmdline,     // command line 
          NULL,          // process security attributes 
          NULL,          // primary thread security attributes 
          TRUE,          // handles are inherited 
          0,             // creation flags 
          NULL,          // use parent's environment 
          NULL,          // use parent's current directory 
          &siStartInfo,  // STARTUPINFO pointer 
          &piProcInfo);  // receives PROCESS_INFORMATION 
       
       // If an error occurs, exit the application. 
       if ( ! bSuccess ) 
          ErrorExit(TEXT("CreateProcess"));
       else 
       {
          // Close handles to the child process and its primary thread.
          // Some applications might keep these handles to monitor the status
          // of the child process, for example. 
    
          CloseHandle(piProcInfo.hProcess);
          CloseHandle(piProcInfo.hThread);
       }
    }
     
    void WriteToPipe(void) 
    
    // Read from a file and write its contents to the pipe for the child's STDIN.
    // Stop when there is no more data. 
    { 
       DWORD dwRead, dwWritten; 
       CHAR chBuf[BUFSIZE];
       BOOL bSuccess = FALSE;
     
       for (;;) 
       { 
          bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL);
          if ( ! bSuccess || dwRead == 0 ) break; 
          
          bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);//这里卡住
          if ( ! bSuccess ) break; 
       } 
     
    // Close the pipe handle so the child process stops reading. 
     
       if ( ! CloseHandle(g_hChildStd_IN_Wr) ) 
          ErrorExit(TEXT("StdInWr CloseHandle")); 
    } 
     
    void ReadFromPipe(void) 
    
    // Read output from the child process's pipe for STDOUT
    // and write to the parent process's pipe for STDOUT. 
    // Stop when there is no more data. 
    { 
       DWORD dwRead, dwWritten; 
       CHAR chBuf[BUFSIZE]; 
       BOOL bSuccess = FALSE;
       HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    
    // Close the write end of the pipe before reading from the 
    // read end of the pipe, to control child process execution.
    // The pipe is assumed to have enough buffer space to hold the
    // data the child process has already written to it.
     
       if (!CloseHandle(g_hChildStd_OUT_Wr)) 
          ErrorExit(TEXT("StdOutWr CloseHandle")); 
     
       for (;;) 
       { 
          bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
          if( ! bSuccess || dwRead == 0 ) break; 
    
          bSuccess = WriteFile(hParentStdOut, chBuf, 
                               dwRead, &dwWritten, NULL);
          if (! bSuccess ) break; 
       } 
    } 
     
    void ErrorExit(PTSTR lpszFunction) 
    
    // Format a readable error message, display a message box, 
    // and exit from the application.
    { 
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD dw = GetLastError(); 
    
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            dw,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR) &lpMsgBuf,
            0, NULL );
    
        lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
            (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
        StringCchPrintf((LPTSTR)lpDisplayBuf, 
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error %d: %s"), 
            lpszFunction, dw, lpMsgBuf); 
        MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 
    
        LocalFree(lpMsgBuf);
        LocalFree(lpDisplayBuf);
        ExitProcess(1);
    }

    子进程:

    #include <cstdio>
    #include <cstdlib>
    
    int main()
    {
    	int i;
    	freopen("input.txt","r",stdin);//去掉这一句就不会卡住
    	while(scanf("%d",&i)==1)
    	{
    		printf("%d\n",i);
    	}
    	return 0;
    }
    

    多谢

    祥杰

    2012年2月7日 8:41

全部回复