dbenham wrote:There must be some kind of timing issue - if there is additional data waiting in the pipe buffer, than SET /P continues reading, but at some point SET /P sees that there is no data waiting, so it triggers the end and SET /P finishes.
I'm not sure if i may misunderstand (this part of) your post.
Do you assume that if the pipe is performing a write, and a read operation then the read operation is blocked (by the pipe) until the write operation is finished (interuptable by timeout)?
The set/P (function) doesn't know how much data will be passed to the pipe (buffer) by a foreign process.
It accesses just the read method of the pipe (via the actual set up (default) input stream).
At this level i have to admit, that it may be possible that someone creates a pipe that has such timeout events, as it is not forbidden (as far as i know; i would have to read into).
But i never have seen such a construct.
All pipe implementation (that i have seen) somehow synchronize the read/write operations.
Such a pipe may then block the write operation if there is more data to write than fits in the pipe buffer, but the write operation never blocks the read operation.
Typically there is another (blocking) read function, that guarantees to read at least one atomic data value.
In most cases this is guaranteed by a cyclic buffer; example:
======
atomic data value field (simple buffer): buffer
offset: start, end // data begins at start index and ends at index end
If the end of the buffer is reached (read/write) the next data atomic data value to process is at index 0, (1, 2, ...).
Contract of all subclasses:
The read operation is only allowed to change the start offset value,
while the write operation is only allowed to change the end offset value.
======
So the pipe read operation returns ((start <= end) ? (end-start) : (buffer.length+end-start)) atomic data values.
It doesn't matter if a write operation is in progress/has partially written its content to the pipe buffer/...: The read operation is non blocking.
Up to now i've not seen a situation in which such a "timing construct" may be useful, and it offers the possibility of (unexpected) deadlocks, so i doubt someone has implemented a pipe that way.
dbenham wrote:I was assuming there must be some kind of timeout, because sometimes I get multiple SET /P sender outputs as one line of input in the receiver. If there were not a timeout condition, then I was thinking that the SET /P loop reading data from the pipe would always be significantly faster than multiple SET /P statements from the sender, so they should all be on separate lines. But sometimes the sender manages to squeeze two SET /P outputs into a single receiver input. I thought the only way that could happen is if there was some kind of timeout condition on the receiver end.
The actual order of write and read operations is influenced by mutlitasking/multithreading/multiprocessing.
If you receive multiple sender outputs in one line, then the "sender just has good luck" on mutlitasking/multithreading/multiprocessing.
For example: The taskmanager in common does not guarantee, that all processes have the same amount of processor time per "step".
dbenham wrote:I don't see how that gives the results we see with SET /P generated input that has no <CR> or <LF>
So how does my SET /P generated input end up as multiple lines lines? The buffer is not full, so why does the receiver generally put each character as a new line? If the SET /P were to continue to read until the buffer were full, then I would expect [h][e][l][l][o ][w][o][r][l][d] all on one line.
Producing one of the the above results. Let A be the data source, B be the sink process ("A|B"), and P be the pipe:
Code: Select all
Process A output Process B
P.write("START 1\r\n", 0, 9); 9 == P.read(var.buffer, 0, 1023); -> var = "START 1"
var=START 1
<pause...>
P.write("[H]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[H]"
var=[H]
P.write("[e]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[e]"
var=[e]
P.write("[l]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[l]"
var=[l]
P.write("[l]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[l]"
var=[l]
P.write("[o ]", 0, 4); 4 == P.read(var.buffer, 0, 1023); -> var = "[o ]"
var=[o ]
P.write("[w]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[w]"
var=[w]
P.write("[o]", 0, 3);
P.write("[r]", 0, 3); 6 == P.read(var.buffer, 0, 1023); -> var = "[o][r]"
var=[o][r]
P.write("[l]", 0, 3); 3 == P.read(var.buffer, 0, 1023); -> var = "[l]"
var=[l]
P.write("[d]", 0, 3);
P.write("END 1\r\n", 0, 7); 10 == P.read(var.buffer, 0, 1023); -> var = "[d]END 1\r\n"
var=[d]END 1
(...) (...) (...)
penpen