So the question is, is there a method of terminating a producer process without the use of an explicit control channel as in the example?
As long as the decision to terminate originates from outside the producer process, there is no other way than to use a (control) channel. It is because in the distributed-memory model the information has to be communicated via a message.
That said, the poisoning method you refer to is a general method, and it can be made to work in this case too. The reason it pollutes the solution is that the original (non-terminating) producer process only sends messages, but does not receive any. For the poisoning method to work, the producer has to be prepared to accept messages, and - what is even more inconvenient - the consumer has to be prepared to deal with a sluggish producer.
I would consider using a different technique to solve the problem: the producer would get a signal after each message sent whether the consumer want it to continue or not. This would result in more traffic, but the structure of the solution is clearer this way.
Occam 2.1 code:
PROC producer( VAL INT start, step, CHAN INT data, CHAN BOOL control)
BOOL running:
INT count:
SEQ
count, running := start, TRUE
WHILE running
SEQ
data ! count
control ? running
count := count + step
: -- producer
PROC main( CHAN BYTE inp, out, err)
CHAN INT data:
CHAN BOOL control:
VAL INT amount IS 10:
INT val:
PAR
producer( 0, 4, data, control)
SEQ n= 1 FOR amount
SEQ
data ? val
control ! n < amount
out.int( val, 0, out)
out.string( "*n", 0, out)
: -- main