Solved

Asynchronous I/O to spawned process

Posted on 2003-10-21
10
1,155 Views
Last Modified: 2013-12-03
Hi!

I want to perform asynchronous I/O on stdout/stdin on a spawned process.
So far i have only been able to do synchronous I/O. I have read that
asynchrounous I/O is possible using named pipes, but i haven't been able
to make it work. Does anyone have a clue?

Some code to illustrate my problem
<-- asyncapp.cpp -->
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

int main(void)
{
      for(int x=10; x--;)
      {
            printf("%d ", x);
            Sleep(1000);
      }
      return 0;
}



<-- redirectedconsole.cpp -->
#define WIN32_LEAN_AND_MEAN
#define BUFSIZE 4096
#include <windows.h>
#include <stdio.h>
#include <conio.h>

HANDLE m_hChildStdoutRd;

DWORD WINAPI readthread(LPVOID lpParameter)
{
      DWORD dwRead;
      TCHAR chBuf[BUFSIZE+1];

      for (;;)
      {
            if(!ReadFile(m_hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) || dwRead==0)
                  break;

            chBuf[dwRead]='\0';
            printf(chBuf);
      }

      return 0;
}

int main(void)
{
      HANDLE hChildStdoutRdTmp, m_hChildStdoutWr, hSaveStdout;
      SECURITY_ATTRIBUTES saAttr;
      PROCESS_INFORMATION piProcInfo;
      STARTUPINFO siStartInfo;
      DWORD id;

      // Set the bInheritHandle flag so pipe handles are inherited.
      saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
      saAttr.bInheritHandle = TRUE;
      saAttr.lpSecurityDescriptor = NULL;

      // Save the handle to the current STDOUT.
      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

      // Create a pipe for the child process's STDOUT.
      if(!CreatePipe(&hChildStdoutRdTmp, &m_hChildStdoutWr, &saAttr, 0))
            return FALSE;

      // Set a write handle to the pipe to be STDOUT.
      if(!SetStdHandle(STD_OUTPUT_HANDLE, m_hChildStdoutWr))
            return FALSE;

      // Create noninheritable read handle and close the inheritable read handle.
      if(!DuplicateHandle(GetCurrentProcess(), hChildStdoutRdTmp, GetCurrentProcess(), &m_hChildStdoutRd, 0, TRUE, DUPLICATE_SAME_ACCESS))
            return FALSE;

      // Close original handle
      CloseHandle(hChildStdoutRdTmp);

      // Restore saved handle
      if(!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
            return FALSE;

      // Set up STARTUPINFO
      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
      siStartInfo.cb = sizeof(STARTUPINFO);
      siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
      siStartInfo.wShowWindow = SW_HIDE;
      siStartInfo.hStdInput = NULL;
      siStartInfo.hStdOutput = m_hChildStdoutWr;
      siStartInfo.hStdError = m_hChildStdoutWr;

      // Create child process
      if(!CreateProcess(NULL, "asyncapp.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &piProcInfo))
            return FALSE;

      // Create read thread
      if(!CreateThread(NULL, 0, readthread, 0, 0, &id))
            return FALSE;

      getch();
      return TRUE;
}
0
Comment
Question by:oskii
  • 4
  • 3
10 Comments
 
LVL 8

Expert Comment

by:mxjijo
ID: 9591865

I dont know if I totally understood what u need to achive but..

In general, most of the I/O access could be made asynchronous by setting proper flags during creation time or later, depending up on what u are creating. For example if you specify FILE_FLAG_OVERLAPPED flag, you can perform async operation on that file.

In your case, as far as I know CreatePipe() doesnot support async operations. But, try CreateNamedPipe() with PE_NOWAIT flag. Then you'll be able to do non-blocking IO operations. Take a look at the following links to see more on async IO operations.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/synchronous_and_overlapped_input_and_output.asp

~ J
0
 

Author Comment

by:oskii
ID: 9592403
Instead of create pipe I have tried to create a named pipe with:

OVERLAPPED OverlapObj;
hChildStdoutRdTmp=CreateNamedPipe("\\\\.\\pipe\\apipe", PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 4096, 4096, 500, NULL);
m_hChildStdoutWr=CreateFile("\\\\.\\pipe\\apipe", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
ZeroMemory(&OverlapObj, sizeof(OverlapObj));
ConnectNamedPipe(hChildStdoutRdTmp, &OverlapObj);

If I then put WaitForSingleObject() in the read thread, it will never return, i suppose something is wrong...
0
 
LVL 8

Expert Comment

by:mxjijo
ID: 9593270

Explain me a little more... how did you do it ?

Did you setup the OVERLAPPED structure properly ?
What id the return value of ReadFile() ??
What hande are you passing to WaitForSingleObject() ?

~ J


0
MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

 

Author Comment

by:oskii
ID: 9593496
I have not done any setup of the overlapped structure (other than ZeroMemory). I dont really know what i shoud fill it with, this might be the problem.
I passed the m_hChildStdoutRd handle to WaitForSingleObject. ReadFile returns nonzero and sets last error to 997 (Overlapped I/O operation is in progress)

Thank you mxjijo for your interest in this question!
0
 
LVL 8

Expert Comment

by:mxjijo
ID: 9594051

Its not the way Async IO works.

Its fine that u're passing Zero'd OV structure to ConnectPipe().

But you have to prepare another one for ReadFile too, which in your case should not be Zero'd.

As you mentioned, your ReadFile() will return immediately with IN_PROGRESS error. Now, you have to wait for that IO operation to compleate. This could be done as follows

* Prepare an OVERLAPPED structure and pass it to ReadFile() with an Event, created prior to this. System will set that event once the IO operation is compleated. Infact this is the handle that you should pass to your WaitForSingleObject().

   Wait - Not ovet yet. Now, once the Event is triggered, you can assume the io operation is over, but there could be an error. So you should check the status of this operation using GetOverlappedResult(), passing the OV structure and Pipe handle above. Now, you have more clear idea how many bytes has been transferred, what eas the result etc.

   You should read up on the link I gave you before. It explains the typical Async IO operation.

~ J
0
 

Author Comment

by:oskii
ID: 9601152
Thank you for your reply, i have not been able to make overlapped I/O work yet, but i am confused weither overlapped communication really solves the main problem, if you compile and run the asyncapp.cpp (you can probably do it mentaly), you will se that it displays 9 <one sec delay> 8 ... and so on when the same program is being executed with redirected stdout it will be a 10 second delay, and after that all numbers are displayed. If i put fflush(stdout) in the loop in asyncapp the application will work as it is supposed to do even when spawned with redirected handles. The problem is that i am trying to redirect a third-party application for which i dont have the sources.

Will overlapped I/O solve this problem, or should i seek answers elsewhere?

Thanks in advice,
Oskar Sjöberg
0
 
LVL 8

Expert Comment

by:mxjijo
ID: 9601331

I have not compiled your code, but as a first impression, I dont think Overlapped IO will NOT solve your problem. I have not tried io redirection my myself yet. However I had a similar problem on Unix I remember, and fflush() was the method I used there either:) Yes there is some buffering assiciated with stdio's. I dont know if there is a way to get aroung this..  I'll let u know if I find something..

~ J
0
 

Accepted Solution

by:
CetusMOD earned 0 total points
ID: 10869862
PAQed, with points refunded (50)

CetusMOD
Community Support Moderator
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question