Jump to content


Do-loops using co_stream functions


  • You cannot reply to this topic
1 reply to this topic

#1 RalphBodenner

    Advanced Member

  • Admin
  • PipPipPip
  • 348 posts

Posted 01 February 2005 - 11:12 PM

The parallel nature of Impulse C and its flexible programming model can lure your code into some tricky synchronization problems that you might not expect. Take this pair of simple processes, for example, connected by a single stream:

CODE
void process_send(co_stream out)
{
   co_int32 i;
   co_stream_open(out, O_WRONLY, INT_TYPE(32));
   for ( i = 0; i < 10; i++ ) {
       co_stream_write(out, &i, sizeof(co_int32));
   }
   co_stream_close(out);
}

void process_recv(co_stream in)
{
   co_int32 data;
   co_stream_open(in, O_RDONLY, INT_TYPE(32));
   do {
       co_stream_read(in, &data, sizeof(co_int32));
       printf("%i\n", data);
   } while ( ! co_stream_eos(in) );
   co_stream_close(in);
}


Looks good, right? It is entirely possible, however, that since both processes may run in parallel, the following sequence of operations could occur:

process_send: co_stream_write: Write the last datum to the stream (9).
process_recv: co_stream_read: Read the last datum (9).
process_recv: printf: Print the last datum (9).
process_recv: co_stream_eos: Check if the stream is empty; returns 0 (not empty). Continue the loop.
process_send: co_stream_close: Close the stream and set the EOS marker.
process_recv: co_stream_read: Attempt to read the stream and detect the EOS marker. Return co_err_eos.
process_recv: printf: The 'data' argument is unchanged, so the last datum is printed a second time (9).
process_recv: co_stream_eos: Return 1, since the stream is empty. Exit the loop.

In this case, the last piece of data read will be printed twice, so it would appear that one extra datum was read from the stream. Since this behavior will only be observed from a specific sequence of operations, it may manifest itself as a mysterious bug.

The solution is simple: check the return value of co_stream_read and break out of the loop if it fails. co_stream_eos is not a blocking function and will not wait for new stream data determine whether a stream is closed or not. Also note that the EOS condition on a stream is only set after it has been closed by the writer, not after all the data have been read.

An improved version of process_recv might look like this:

CODE
void process_recv(co_stream in)
{
   co_int32 data;
   co_stream_open(in, O_RDONLY, INT_TYPE(32));

   do {
       if ( co_stream_read(in, &data, sizeof(co_int32)) != co_err_none ) {
           break;
       }
       printf("%i\n", data);
   } while ( 1 );
   co_stream_close(in);
}


As a general rule, checking co_stream_read's return value is A Good Idea. cool.gif
Ralph Bodenner
Impulse Accelerated Technologies, Inc.

#2 gchow

    Member

  • Members
  • PipPip
  • 4 posts

Posted 08 September 2009 - 01:17 PM

What about co_stream_write, the documentation says that it too can return a co_err_eos, I take that to mean that it should detect if the receiver has prematurely shut down the stream while the sender is still active, I don't seem to be getting that instead the sender happily sends things along until it fills the FIFO and blocks. I was really hoping for a more graceful exit in that the sender will detect the stream was shut down and then it proceeds to wind down itself and hence all upstream processes from that point on.

Gloria





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users