Link to home
Start Free TrialLog in
Avatar of meessen
meessen

asked on

select and WaitForMultipleObjects

Hello,

I'm writing a small program that needs to wait on socket I/O and on process I/O using pipes.

To detect pipe I/O I must use WaitForMultipleObjects and for socket I/O I must use select.
These waits are incompatible. I can't even interrupt one if there is data to forward bewteen them.
Is there a way to use select or WaitForMultipleObjects to wait for all types of event without needing to poll ?

Do I have to go for threads where I could avoid it in unix ?


ASKER CERTIFIED SOLUTION
Avatar of abesoft
abesoft

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of meessen
meessen

ASKER

The good news is that I use Windows socket implementation.

I created a listening socket and passed it to WaitFor MultipleObjects but apparently the object doesn't become signaled when a connection is done. So I stay with a pending connection. This might be THE exception.

It would be great if I could wait for incomming connections,socket I/O, child processes death and child process I/o through pipe in a single call.

Unfortunately the incomming connection did never signaled the object so I did not test the rest. It's useless unless you can confirm to me that it should work and the problem might be in my code.

Beside I need to port this beast on unix.
Avatar of meessen

ASKER

The good news is that I use Windows socket implementation.

I created a listening socket and passed it to WaitFor MultipleObjects but apparently the object doesn't become signaled when a connection is done. So I stay with a pending connection. This might be THE exception.

It would be great if I could wait for incomming connections,socket I/O, child processes death and child process I/o through pipe in a single call.

Unfortunately the incomming connection did never signaled the object so I did not test the rest. It's useless unless you can confirm to me that it should work and the problem might be in my code.

Beside I need to port this beast on unix.
Avatar of meessen

ASKER

I checked again for WaitFor... with a listening socket and it doesn't work. It works well with select.

Select signals an error when given a Process handle or a pipe handle. This behaves as documented.

And the answer is .....

WSAEventSelect !

This makes my code portable ! Great !


Avatar of meessen

ASKER

Well of course WSAEventSelect is documented but is not provided in the library and most probably not implemented. Thank you M$...

Any other idea ?
Avatar of meessen

ASKER

Now suppose I want to use two threads. select is used for socket io thread.
And WaitFor... in a child process listening thread.
I could use event objects to unblock a WaitFor when network data has come in.
But how do I unblock a select ?

This means that the WaitFor... must do the socket send using non blocking calls.

Excuuuse me be this is getting really twisted for what look like a very simple and academic application. And we can definitively forget about protability here.

I'm desperate... and this work is soo urgent as usual !
If you want portable code, have you considered using ACE?  It is a library that encapsulates a lot of multiprocessing and communications concepts, and is quite extensive.  Check out http://www.cs.wustl.edu/~schmidt

It might be your best bet to get this thing running on both platforms....
Avatar of meessen

ASKER

I know ACE but I don't have time and the experience to use this package.

I now have a input thread imlementing the select operation for new connection and incomming data on sockets. I use event to signal incomming data.

I have a main thread using WaitFor... and it works fine. Well nearly fine.

The problem left is that when I start the process using pipes to redirect I/O I check the child process output pipe if it is signaled. Apparently it is but When I try to ReadFile on it the call blocks. And of course everything blocks since I never go back to the WaitFor and give other task a chance  to be executed.

Any clue on what could make this ReadFile block ?

I have a buffer of size BUFSIZE.
I do ReadFile( proc->stdout, buffer, BUFSIZE, &len, NULL );


If I manualy kill the child process, the pipe is released, and the read is terminated.
I know the process is sending an output line.

What I don't understand is why the output pipe handle is signaled and a ReadFIle will block !


Avatar of meessen

ASKER

Even worse....

I have written a small dummy program doing the following:
int main( int argc, char* argv[] ){
      HANDLE so;
      long len;
      char msg[] = "+ Hello\n";

      for( ;; ){
            int i;
            printf("- hello\r\n");

            so = GetStdHandle(STD_OUTPUT_HANDLE);
            WriteFile( so, msg, strlen(msg), &len, NULL );
            for( i = 1; i < 50000; i++ )
                  i = (i*2)/2;
      }
      return 0;
}

When run from the console I get
+ Hello
- hello
+ Hello
- hello
+ Hello
- hello
+ Hello
- hello
+ Hello
- hello
as expected.

Now run as a child process and doing a synchronous ReadFile on the stdout handle I get
A big bunch of + Hello and suddently a big bunch of - hello.
I didn't check but I guess the number of output lines is the same.
Very usefull feature.

We are now going to evaluate Linux and solaris on Intel for our 3.5 Million Dollar project.





Problem one: ReadFile doesn't return until the piped task terminates.
This is a direct result of what ReadFile is doing: Reading data until EOF.  You don't get an EOF on stdin until the process that is piping to you terminates, or the buffer is exceeded.  What I think you want to do is to read in data in smaller chunks (a byte at a time, maybe?) and process it as you see it.  You might also want to consider overlapped I/O, so you can properly handle time-outs on the input....

Problem two: Unsynchronized I/O
I think you need to flush stdin/stdout to get the two streams synchronized.  Try this:
int main( int argc, char* argv[] ){
    HANDLE so;
    long len;
    char msg[] = "+ Hello\n";

    for( ;; ){
        int i;
        printf("- hello\r\n");
        fflush( stdout);

        so = GetStdHandle(STD_OUTPUT_HANDLE);
        WriteFile( so, msg, strlen(msg), &len, NULL );
        FlushFileBuffers( so);
        for( i = 1; i < 50000; i++ )
            i = (i*2)/2;
    }
    return 0;
}