Solved

Asynchronous I/O to spawned process

Posted on 2003-10-21
10
1,152 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
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
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…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

839 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