我用下面的代碼創(chuàng)建一個子進程,,并用兩個管道去重定向它的標準輸入輸出,。子進程是一個交互式的命令行程序,其流程為:接受標準輸入,,運算,,將結(jié)果送標準輸出,然后繼續(xù)接受輸入,,再遠算輸出,,一直重復。父進程利用這兩個管道來操作子進程的標準輸入輸出,,其流程為寫子進程標準輸入管道,即讓子進程接受標準輸入,,然后讀子進程標準輸出管道,,接收子進程標準輸入,然后再重復此過程,。發(fā)現(xiàn)了一些有趣的問題:1,,printf在重定向管道后不靠譜,比如,,子進程的prinf內(nèi)容不能被管道讀取到,,我猜想是存在buffer沒有寫到管道中的問題,在子進程中用fflush(stdout)后,,管道可以讀取到,。2,在子進程中用c++的std::cout沒有此問題,,子進程的流程是 std::cin>>x, 再std::cout<<y,再std::cin>>x,,std::cout<<y,依次重復,,在第一次std::cout<<y后,,它后面的std::cin>>x居然會在父進程還沒開始寫管道時就執(zhí)行,只不過讀出來的數(shù)據(jù)是空,,這與子進程單獨運行不一樣,,單獨運行時,在第二次std::cin>>x時會阻塞在那等待標準輸入,,而在標準輸入被重定向到管道后,,它在第一次std::cin>>x時已經(jīng)讀取了管道內(nèi)容了,在第二次std::cin>>x時,它沒有等待父進程寫管道,,而是直接就讀取空串返回了,,在第一次之后的std::cin>>x之前加上fflush(stdin)后,就沒有此問題了,。我試驗在父進程中來做flush管道的操作,,都不能解決此問題。 我想與大家討論的是,,如果我想寫一個父進程來交互式地控制子進程的標準輸入輸出,,有沒有辦法只在父進程的代碼上做文章,使父進程能順利地與子進程交互,,不管子進程是用scanf, printf, cin, cout還是其它的做標準輸入輸出的方法,。畢竟對于有些已經(jīng)存在的程序,它沒有用cin, cout,,也沒有在cin前做fflush(stdin)的操作,? 另外順便問下大家,我在VS2003中加了兩個工程,,一個子進程,,一個父進程,有沒有方法讓我可以同時調(diào)試這兩個進程,,比如我將子進程工程設(shè)置為父進程工程的reference,,父進程設(shè)為啟動工程,在子進程的代碼處打上斷點,,然后運行就可以在子進程代碼的斷點處停下,。如果是dll,這個完全沒有問題,,也許進程就不行,,不曉得大家知道有方法這樣做沒?我記得注冊表中好像有個目錄,,在里面加上子進程的可執(zhí)行文件名,,就可以設(shè)置其啟動,調(diào)試參數(shù),,如果將它設(shè)置為在VS2003中啟動,,也許就可以調(diào)試它了,不知這樣是否可行,? 文字能力不強,,篇幅多了,希望大家見諒,。 啟動子進程代碼: PROCESS_INFORMATION pi; bool BridgeStart(char* target_name) { BOOL bSuccess; /* BOOL return code for APIs */ SECURITY_ATTRIBUTES sa; STARTUPINFO si; /* set up the security attributes for the anonymous pipe */ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // create anonymous pipe bSuccess = CreatePipe(&hHostRead, &hSlaveWrite, &sa, 0); //PERR(bSuccess, "CreatePipe"); // create anonymous pipe bSuccess = CreatePipe(&hSlaveRead, &hHostWrite, &sa, 0); //PERR(bSuccess, "CreatePipe"); /* Set up the STARTUPINFO structure for the CreateProcess() call */ ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = hSlaveRead; si.hStdOutput = hSlaveWrite; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); /* Set up the PROCESS_INFORMATION structure for the CreateProcess() call */ ZeroMemory( &pi, sizeof(pi) ); // Start the child process. bSuccess = CreateProcess(NULL, // No module name (use command line) LPTSTR(target_name), // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance to TRUE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi); // Pointer to PROCESS_INFORMATION structure //PERR(bSuccess, "CreateProcess"); if (bSuccess) return true; else return false; } 讀寫子進程輸入輸出管道代碼: int BridgeRead(char* buf, int len) { BOOL bSuccess; /* BOOL return code for APIs */ DWORD n; /* number of bytes read or to be written */ bSuccess = ReadFile(hHostRead, /* read handle */ buf, /* buffer for incoming data */ len, /* number of bytes to read */ &n, /* number of bytes actually read */ NULL); /* no overlapped reading */ if (!bSuccess && (GetLastError() == ERROR_BROKEN_PIPE)) return(-1); else return(n); } int BridgeWrite(char* buf, int len) { BOOL bSuccess; /* BOOL return code for APIs */ DWORD n; /* number of bytes read or to be written */ bSuccess = WriteFile(hHostWrite,/* write handle */ buf, /* buffer to write */ len, /* number of bytes to write */ &n, /* number of bytes actually written */ NULL); /* no overlapped writing */ if (!bSuccess && (GetLastError() == ERROR_BROKEN_PIPE)) return(-1); else return(n); } 子進程代碼 int _tmain(int argc, _TCHAR* argv[]) { int a,b; while(1) { fflush(stdin);//如果此行去掉,,重定向輸入輸出到管道后就會出問題,。 std::cin >> a >> b; std::cout << a + b << std::endl; } return 0; }
相關(guān)帖子推薦:
|
|
來自: firefox_zyw > 《待分類1》