kent logo

CO538 Anonymous Questions and Answers

This page lists the various questions and answers. To submit a question, use the anonymous questions page. You may find the keyword index and/or top-level index useful for locating past questions and answers.

We have taken the liberty of making some minor typographical corrections to some of the questions as originally put. Although most of the questions here will have been submitted anonymously, this page also serves to answer some questions of general interest to those on the course.

When asking questions, please do not simply paste in your code and ask what is wrong with it, as these types of question are hard to answer in a public forum (resulting in either no answer, or an answer which will only be of use to the person asking the question). In many cases, a question about code can be formulated in general terms. For example, if you have an `IF' block that results in an `incorrect indentation' error, you might ask, ``what is the correct syntax for an occam `if' statement ?''. Questions of this form are easier to answer, and are meaningful to all.

Questions that are not suitable for these public pages (i.e. those that contain assignment-specific code), should be mailed to your seminar-leader.

Question 35:

Submission reference: IN2189

Is there a way to join strings together easily? For example, in Java you can just use '+'. Thanks.

Answer 35:

Classical occam was definitely not designed for string handling, :(. Strings are BYTE arrays and arrays have fixed lengths, with those lengths fixed at compile time, :( :(. For further Q&As on string difficulties, follow the lilnks to "strings" and "string-handling" in the keyword index.

We did provide a string handling library but it's painful to use. A string has to be maintained in two variables: a BYTE array sufficiently long and an INT recording its actual length. (Aside: with occam-pi, this could be simplified to a single RECORD variable – see "Shared-etc" slides 94-116 – but it would still be a painful.) If an attempt is made to extend a string beyond the size allowed by the BYTE array, it just crashes! To try it out (not recommended), include:

    #INCLUDE "string.module"

in your program.

However, occam-pi has dynamic arrays whose size is set at run-time, which means they can also be changed – see "Mobiles" (which is not an examinable part of this course) slide 14. Further, occam-pi has user-defined operators and user-defined types, which means that a library can be set up defining a dynamic STRING type and a whole bunch of infix operators (e.g. "+" for joining them). This would be a useful mini-project (or part of a larger one).

Having said the above, why do you want to join strings together for this assessment (Dining Phils Animation)? The college processes should not be working with strings – see the last paragraph ("Do not attempt ...) of the answer to Question 31 (2012). Only the display process needs to deal with strings and, then, only to output them to the screen!. To "join" strings together for such output is unnecessary – simply output them in sequence.

Keywords: q7 , strings , string-handling

Question 34:

Submission reference: IN2194

I'm having an issue with setting up my Shared Channel, I have got my protocol REPORT, with the TAGS and INT value to store the philosopher or fork using that channel. I'm struggling with how to pass the ID of the phil or fork to the actual REPORT protocol.

        thinking; INT
        ...  (Ed: rest hidden)

    PROC fork (CHAN BOOL right?, left?, SHARED CHAN REPORT report!, CHAN INT id?)
      ...  (Ed: code body hidden)
    PROC secure.college (SHARED CHAN REPORT out!)
      ...  (Ed: rest of code body hidden)

    PROC display (SHARED CHAN REPORT out!, CHAN BYTE screen!)
      ...  (Ed: code body hidden)

I keep getting type mismatch for parameter 4 in fork and 6 in philosopher. I've tried a lot of ways to try and get the 'i ' value into the other processes, I want to be able to try and have a look at my display process, but I can't test this until I can actually get it to compile.

Is there a glaring error, or am I approaching this in the completely wrong way.

Answer 34:

There is a glaring error – but it's easily fixed.

To give a single value to a process (that will not need updating by some other process as it runs), pass that value as a VAL parameter – not a channel! A process needs a channel input-end to receive information that is not available when it is created and, usually, on more than one occasion.

Parameter 4 in your fork header is declared as a channel. In your secure.college, you instance each fork with the control value, i, as its fourth argument. You can't pass an INT value to a parameter expecting a channel – hence, the "type mismatch" error reported by the compiler. You try to avoid this by actually passing the text "i?" as the fourth argument (maybe hoping that might convert the INT value to a channel delivering that value?). The compiler correctly rejects this.

Inside your fork process, you try to read from that id? channel (the fourth parameter). That will compile, but no process ever sends to it ... so the fork would get stuck at that point.

Solution: change the fourth parameter of fork from a channel to a value:

    PROC fork (CHAN BOOL right?, left?, SHARED CHAN REPORT report!, VAL INT id)

Inside its body, just use id when it makes a report. Make similar changes to your philosopher process (not included in your question). Inside secure.college, instance the fourth argument of fork with the PAR replicator i. Done! :)

Not relevant to the above, you included part of your display process in your question – its header is shown in the question. Its first parameter is very wrong (possibly a cut-and-paste mistake?). This is the REPORT channel and it should be for input (not output). Further, it's not SHAREDdisplay is the only process that has to read from it.

Final point: inside your secure.college, you declare another channel carrying the REPORT protocol, also SHARED at the writing-end. Why? The parameter channel, out!, is the one on which reports must be made. You plug the shared writing-end of this new channel, r!, into the report arguments for all college processes – so that is where they will write. Unfortunately, nobody is listening to the other end, r?, so they will all block the first time they try to report, :(. Fix: delete the declaration of channel r and plug out! into the report arguments of the college processes.

Keywords: q7 , shared-channel

Question 33:

Submission reference: IN2191

I'm trying to write a display process for q7 so I can get it working, but I'm completely stuck at this very early stage....

The lectures seemed to suggest that this could be done with a replicated ALT running across all 11 items in the channel array, but I don't know how to do this as:

    ALT i = 0 FOR SIZE in?

will do it for all the items in the array ... but, if I want to differ my messages for the security guard compared to the forks and the philosophers, I will need to have a nested replicated ALT that is FOR (SIZE in? - 1) and then the 11th one for the security guard will be a normal guard under that?

Alternativley, I could rethink the whole thing and do it using a different numbering system on the report channel but then I read Question 31 (2011) and was totally confused by what is meant by:

"The philospher that picks up fork id on its right channel is philospher (id + 1)\n.phils."

Surely if philosopher 1 picks up fork 1 on his right then philosopher (1 + 1) / 5 is 0?

What is the suggested way for writing the display process at this early stage? Is a replicated ALT the best / only way or is writing out each and every statement as a guard acceptable (as this is the only way I can think of getting it to work)?

Answer 33:

If you have an array of 11 report channels (as in "Applying" slides 64-65), then the simplest way to handle them in the display process is via a replicated ALT.

To work out whether the report is from the security guard, a fork or a philosopher, you don't need to nest a slightly less replicated ALT (listening to the first 10 channels from the phils and forks) within an ALT that listens also to the 11th (from security). Nor do you have to replicate the guarded processes 11 times by hand.

Look at "Choice" slide 116 and suppose that its n is 11. In the response to the guard, just test the value of i (e.g. using an IF). If i is between 0 and 4 inclusive, it's a phil report. If i is between 5 and 9 inclusive, it's a fork report. If i is 10, it's a security report.

Of course, your code should not contain magic numbers like 4, 5, 9 and 10. Those numbers depend on how many phils there are (which equals the number of forks) and that is a named constant, n.philosophers, given in your starter code file. Instead, use relevant formulae (n.philosophers - 1, 2*n.philosophers etc.). Then, should anyone wish to change the number of phils in the system, only that constant has to be changed – they don't need to hunt down all the magic numbers that depend on it.

NO CODE SHOULD HAVE MAGIC NUMBERS other than 0 and 1 (and only then if they don't depend on some system value and are 0 or 1 by chance) – except, of course, when declaring names for them. The rest of the code should use the names (or formulae that use the names). This is just good engineering.

You have mis-read the answer to Question 31 (2011). The formula is:

    (id + 1)\n.phils

where the "\" symbol means modulo, not divide. So, if the fork id is 1, then the philospher who has picked it up (on the fork's right? channel) has the number given by the above formula:

    (1 + 1)\5

which is 2\5, which is 2.

Looking at "Applying" slide 29 (referenced in Question 31 (2011)), let's assume that the code gives the phil and fork being replicated an id equal to the replicator control value i. In that case, the fork with an id of 1 is connected to channel-ends left[1]? and right[2]? and is the fork in position 4 o'clock in the network diagram. The phil connected to that fork's right channel is at position 5 o'clock in the diagram and is the phil with id value 2. So, the above formula got it right! ;)

Keywords: q7 , magic-numbers

Question 32:

Submission reference: IN2192

I'm quite far in Assessment 4 now   the only thing I need to get working is the animation!

I have a good idea for an animation and I can implement it correctly, but I come across a problem when using:

    PROC cursor.x.y (VAL BYTE x, y, CHAN BYTE out!)

My problem is that I need to use id (the reporting philosopher's id) in cursor.x.y so that I can line everything up correctly (in my code, the placement of Philosopher id and all of its reports is going to be relative to its actual id). However, when I try to do something like:

    cursor.x.y (1, id + 5, out)

this does not work, because cursor.x.y requires BYTEs for its first two arguments and my id (and, hence, id + 5) is an INT.

I think there's a really obvious step of conversion I'm missing here, but I just can't get my head round and find it. I need to convert my id INT into a BYTE. But how do I go about doing that?

Answer 32:

See Question 23 (2008), "Basics" slide 30, and casting.occ in your examples folder. This is also answered in Question 89 (2003), at some length in Question 73 (2000), in a way that may be useful for an animation is Question 66 (2000), and in Question 7 (2000).

For information on the subtleties of casting between number types (which may be useful for the next Assessment 5), see Question 111 (2003).

All the references above to previous items from these anon Q&As were found by following the "keyword index" link (at the top of each Q&A page) and the keyword "cast".

Keywords: q7 , cast

Question 31:

Submission reference: IN2184

In q7, I have implemented the first six stages as best as I could, but it falls down somewhere, and I'm not sure where. Currently, my Philosophers report when they're:

My forks report when:

My security does not yet report.

My philosophers have fixed times for thinking and eating, 5 and 8 respectively.

Now, here's the problem. My program starts out fine. Every philosopher thinks for 5 seconds and all the labelling on the screen is correct. However, problems occur when the thinking stage is over. All 5 philosophers want to sit down, obviously. Philosophers 1-4 get to the table every time, Phils 1-3 pick up one fork each and Phil 4 picks up two forks. Phil 0 is NOT sitting at the table, but here is my console output:

    Philosopher 0 is thinking.
    Philosopher 1 is thinking.
    Philosopher 2 is thinking.
    Philosopher 3 is thinking.
    Philosopher 4 is thinking.
    Philosopher 0 wants to sit down.
    Philosopher 0 is eating.
    Philosopher 1 wants to sit down.
    Philosopher 2 wants to sit down.
    Philosopher 3 wants to sit down.
    Philosopher 4 wants to sit down.
    Philosopher 1 has picked up their left fork.
    Philosopher 2 has picked up their left fork.
    Philosopher 3 has picked up their left fork.
    Philosopher 4 has picked up their left fork.
    Philosopher 4 has picked up their right fork.
    <<System crashes after this>>

Obviously, my fault is on line 7, when Philosopher 0 begins to eat even though he isn't even sat down. Philosopher 4 should be the one eating and the message should show up AFTER he's picked two forks up.

I'm really stumped as to why this has happened. I guess my questions are: Is this happening because of WHERE my reports are placed? Is this happening because of the KIND of reports? (I've used a CASE protocol for this part.) Are there any reasons this could happen?

Answer 31:

Your philosopher needs to send some more messages so that we can see what state it has reached. Presumably it says it "wants to sit down" before it signals on its down channel (to security) and "eating" after it has picked up both forks? But there's a state in between: after its down signal has been taken, it should report that it's "in the dining room, sitting at the table" – otherwise, we won't know that it's got past the security guard. Part of your output was:

    Philosopher 0 wants to sit down.
    Philosopher 0 is eating.

But there's a missing state that we need to see.

It's not impossible for the phil to report that it's eating before the relevant forks report that they have been picked up by this phil. The phil and two forks are trying to make those reports concurrently and the display process may pick up those reports in any order (and, indeed, interleaved by reports from other agents within the college). What seems to have happened is that display processed the phil report (that it was eating), then some other reports and then the system crashed (for some reason to be discovered) before it got round to dealing with the missing fork reports. See Question 28 (2012) for further discussion on such (apparent, but not really) out-of-order reports and how to fix them.

In your output, the forks used by phil 4 say they have been picked up and the system crashed before phil 4 got its report in that it was eating. As above, the scheduling could equally have resulted in the phil 4 eating report to appear before the fork pick-up reports.

Finding the error causing the crash is high priority. Check that all the channels are connected correctly. You said you are using a variant (CASE) protocol. Make sure the receiving display process is programmed to receive all variants being generated by the college processes – if you've left some for later, the system will crash as soon as one that it doesn't handle is sent. See also Question 70 (2000), Question 30 (2003), Question 103 (2003) (the answer), Question 63 (2010) and Question 6 (2011).

For the record, the reports mentioned above used quoted strings in my text. You have used tags from a variant protocol for this, which is great. If anyone is tempted to use actual strings for these reports, please read on.

Do not attempt to program the college processes to output strings (i.e. byte arrays, []BYTE) on their report channels! This would be bad engineering for two reasons. Most serious is that you are binding aspects of the look-and-feel of the display animation (the text in those strings) into the various college processes. When you want to change that look-and-feel (and you will), you would have to go back to those college processes and change them. Separate the look-and-feel of the animation from the logic within the college processes by making their reports plain integer codes (or, better, tags defined by a variant protocol) and do the look-and-feel stuff elsewhere (e.g. in the display process, which can generate appropriate text for the codes/tags received). Then, the look-and-feel can be altered without touching any logic within the college processes. The other poor engineering from getting the college processes to send text is that it takes (much) more processor time than sending codes/tags.

Keywords: q7

Referrers: Question 35 (2012)

Question 30:

Submission reference: IN2186

I have been running the Transterpreter from my own laptop without any problem up to now. However, it has suddenly given the following message when trying to compile any source file, including those in the examples folder:

    Command failed: C:\\(...)\\bin\\occ21.exe -t8 -zqa -etc -w -y -znd -znec
    -udo -zncc -init -xin -mobiles -zrpe -zcxdiv -zcxrem -zep -b -DEF
    OCCBUILD.TVM C:\(...)\(filename).occ
    compile exited with error code: 1

When I try to run the program (in this case, my q7.occ) anyway, I receive the error message:

    Failed to load/decode q7.tbc
    C:\(...)\bin\tvm.exe: failed to load user bytecode.
    q7.tbc exited with error code: 1

I have re-downloaded the Transterpreter and still receive the same error. Is there an issue that has suddenly appeared with my machine, or is there an easier fix?

Answer 30:

Were there any lines of output before the "Command failed" message? If your problem still exists, please get in touch with your seminar leader directly (bringing your laptop).

Keywords: transterpreter

Question 29:

Submission reference: IN2182

I'm using a shared channel, and I managed to get one line to output, but then I get "error: 1" which I believe is a deadlock.

    CLAIM report?
	secure.college (report!)	 -- some parameters will be needed
	display (report?, screen!)	 -- and a 'display' process ..

This is in the main method. The deadlock is supposedly at display. I assume this means that either that line itself is causing a deadlock or the method it is calling.

    PROC display (CHAN P.REPORT report?, CHAN BYTE out!)
      ...  (Ed: some code hidden)

That's the beginning part of my display method. P.REPORT is a protocol that inherits from P.PHIL, P.FORK and P.SEC, which are protocols for the reports from philosophers, forks and security.

I've stared at it for ages and I can't seem to work out what is causing a deadlock.

Any advice? I was thinking perhaps if I made it so its a shared channel at both ends it might work, but I can't seem to work out how to do the solution part mentioned on slide 24 of the shared etc slide. If I do need this (or it is the easier way to fix this) could you give me an example of how i'd implement it.

Answer 29:

Eleven processes within the college want to write to your SHARED report channel. Only one process (display) reads from it. Therefore, your report channel needs to be shared only at the writing end. Your declaration shares it at both ends. See "Shared-etc" slide 5 for how to share only the writing end. All college processes given the writing end of the report channel (in their parameter lists) must declare that writing end as SHARED. The display process, which is the sole holder of the reading end, must not declare it to be shared.

CLAIMing a shared channel-end should be done only when it is about to be used and the claim must not linger beyond that use (i.e. the body of the CLAIM must be as short as possible in execution). Your CLAIM on the report channel is made to enclose the whole system, so it lasts forever! Inside a CLAIM block, the code has exclusive use of the channel-end – it is no longer SHARED, so only one process in your secure.college will be able to be connected to it (the compiler won't allow more if you have done this).

So, do not make the CLAIM where you are making it. The college processes will then be allowed to be connected to the report channel writing-end and they must make the claim each time they want to use it. Inside each claim, they can use the channel-end as many times as they like (and no other processes can interrupt this to use it themselves). This may be useful for certain kinds of animation. To begin with though, they will use the channel-end just once within each claim.

Fix these things and see if the deadlock goes away. On your final paragraph: do not make the report channel shared at both ends (only the writing-end is shared) and the problem described in "Shared-etc" slide 24 is not relevant for this system (when a college process uses the report channel, it uses it only briefly to write a single message informing of its state).

Keywords: q7 , shared-channel

Referrers: Question 37 (2012)

Question 28:

Submission reference: IN2185

In my dining phils system, the displayed messages are out of order. For example, "philosopher n at table" prints before "there is 1 philosopher in the dining room".

Also, the philosopher appears to eat before the right fork has been picked up. I'm sure that it's only the displayed messages that are out of sync, and not the actually philosophers/forks.

I take it this isn't an expected behaviour?

Answer 28:

I will assume that it's philosopher 'n' that sends the report that causes your display process to output "philosopher n at table"? And that this report is made by the philosopher just after sending on the down channel to security?

I will assume that security sends the report that causes your display process to output "there is 1 philosopher in the dining room"? And that this report is made by security upon receiving the down signal from that philosopher?

In which case, we have two processes – philosopher 'n' and security – both trying to send on their report channel to the display process and these two processes are running in parallel. We cannot, therefore, predict which process will send its message first. With the Transterpreter, it depends on the scheduling. With kroc compiled code running on multicore, it also depends on the scheduling and may also happen at the same time. Either way, your display process will see one or both messages pending. If it sees only one, it could be either one. So the order in which those message appear is not predictable – either order is fair enough.

If we really want the security message (that the number of phils in the dining room has changed) to appear before the phil causing that change announces that it is in (or has left) the dining room, this can be arranged. A simple way to do this is to program the input guards in security as "extended inputs" (see Shared-etc slides 53-54) and make the report (of the number change) within the "rendezvous block". Slide 55 shows how to do this without extended inputs, "??", but it's tedious and means the phil codes have to be changed as well.

Your second paragraph describes a philosopher reporting that it is eating before the right fork reports that it has been picked up. This is a different manifestation of the same problem.

I'll assume the phil makes the report that it's eating and the forks report they have been picked up. This time, there are three processes – two forks and a phil – that are trying to report in parallel and that means the order in which display picks them up can be any. Again, this can be constrained by programming the input guards in the fork process with extended inputs and making the fork report within that rendezvous (with the "wait to be put down" input in the optional response part, outside the rendezvous). This way, the fork reports will both be made (in either order, but that's OK) before the phil picking them up completes its "pick up" communications and can make its report.

So, the behaviour you describe is not unreasonable. If processes running in parallel get into a state at the same time (because that state follows a communication between them) where they make independent reports, then those reports may happen simultaneously or in any order. To control the ordering, one or other of the processes must be prevented from getting into that reporting state until its partner has made its report. This is most easily programmed with an extended rendezvous by the process receiving the communication that triggers the reports.

See also Question 27 (2010) and Question 106 (2003).

Keywords: q7

Referrers: Question 31 (2012)

Question 27:

Submission reference: IN2179

Hello, I have everything working fine but I remember in one of the answers previously that you suggested speed.control to ALT between 3 guards, a timeout guard, a speed control guard and an input guard. I was wondering if there was any difference between that 3 guard ALT and a PRI ALT with just a speed control guard and a timeout guard, which is what I currently have.

Answer 27:

Certainly there will be a difference. For one thing, it means when speed.control is waiting for its normal input, it can't process speed control commands. For this exercise, that probably doesn't matter since input data will mostly be pending and it won't have to wait for long. For other applications of speed.control, where the input data was sometimes stalled, this could be bad – it would hold up whatever process was trying to change the speed (and if that process were also interacting with whatever was supplying the input data, that would cause deadlock).

However, not dealing with such possibilities will only be lightly penalised ... this time! Unnecessarily constraining the way a process can sync with its environment is something always to avoid.

The PRI in your question is not relevant to the above concern.

Keywords: q4

Question 26:

Submission reference: IN2178

Hello there,

For Q4 all seems well in Gaul, however there is just one issue. Originally, when the BELL character is output (BELL flashes my output window), the ability to change speed stops, all output stops as well. Is this the desired beaviour or should it be that output continues? I have it so that output will continue such that when the limit is reached the value fed into pause is halved if at 256 lines per second (or doubled if at 1 lines per second) before the bell is output. That way the the limit is reached and imediately reset to the previous speed and the error is shown. Which way is better or desired?

Also is the diagram compulsory? My ASCII art isn't exactly da Vinci standard.

Thank you for your help.

Answer 26:

It is not desired behaviour that the system stops working when a command to change speed would push that speed outside its defined limits. As the question says:

"... the attempt should be ignored and an error message generated. To keep things simple and not interfere with the columns of numbers being output, this error message should be a single BELL character ... sent to the error! channel."

You said: "when the limit is reached the value fed into pause is halved if at 256 lines per second (or doubled if at 1 lines per second) before the bell is output." That implies you do not allow your system to reach either of the defined limiting speeds? If so, that is wrong. What should happen is that if the command would push the speed above 256 lines/second (respectively below 1 line/second), the speed should be changed to 256 lines/second (respectively 1 line/second).

The two diagrams (for pairs2 and q4) are compulsory. You do not have to do ASCII art! There are four options:

Keywords: q4 , diagrams

Question 25:

Submission reference: IN2177

I have tried my best at implementing the approach that was suggested in my seminar where I take the raw BYTE information from print.streams, feed it through my monitor process which implements the freeze functionality and then feed it through a speed.control component before outputting it to the screen!.

Unfortunately, what I thought worked for this approach doesn't seem to and just introduces deadlock when the program first runs. I've written everything out as a diagram and can't get my head round why this is happening - it all looks as if it should work (to me anyway!)

Copied below are the relevant sections of my code. I wondered if you would be able to give me any suggestions of what's happening or why the deadlock is occurring and/or what would be the best way for me to implement the final stages of speed control? Freeze/flip etc. are all working.

Thank you very much in advance for your help.

(Ed: code deleted)

Answer 25:

I've contacted the seminar leaders ... who all deny suggesting the approach you describe. We think you must have misunderstood some of the discussion on this.

See the third and fourth paragraphs of the answer to Question 21 (2012). The approach you describe appears attractive but, for the reasons described in that third paragraph, is unsafe. Deadlock is very likely to happen as soon as a cycle of communications is attempted (whenever monitor communicates to one of the processes it is controlling ... all of which are feeding back communications to monitor). A safe design is outlined in the fourth paragraph just referenced.

You said your implementation of this (wrong) approach "introduces deadlock when the program first runs". The deadlock in that approach only happens when monitor responds to a command to reset one of the three resettable components. If you get deadlock as it starts (i.e. without keying in 'n', 'i' or 'p'), you have another problem – check your wiring, check your speed.control has a loop, ...

Thought: it may be that you misunderstood your seminar leader when the freeze control in Exercise 3 was being discussed? In that system, "the raw BYTE information from" demo "is taken and fed through" a control "process which implements the freeze functionality". Now, there is no feedback loop of message traffic in the network for that exercise – so this is safe. Your seminar leader may have said that exactly this approach also works for Exercise 4 and that is true, but not the way you have taken it. A freeze.control process placed between print.streams and the external screen! channel is good. But that freeze.control process is not the monitor – it is a different process, something extra.

Re. other bits of your code: your speed.control has an ALT with only one guard – see the third paragraph in the answer to Question 14 (2012). I think you mean to poll that channel (i.e. you need to PRI ALT that guard against a SKIP, see "Choice" slide 30).

Keywords: q4

Question 24:

Submission reference: IN2176

For the diagrams for Assessment 3, do you want us to label the channels or just leave them unlabelled? Thanks.

Answer 24:

See the last paragraph in the answer to Question 23 (2012).

Keywords: q4

Question 23:

Submission reference: IN2175

For the graphs, the email said we must provide diagrams for pairs2 and:

    - your overall "q4" network.  Along with other processes, this should show
      the modified "numbers2", "integrate2" and "pairs2" just as black boxes
      (no internal details, as in the diagram on page 5 of 'more-exercises.pdf').

Do you want the internal details of monitor, speed, freeze, print.streams? Or just show the channels?

Answer 23:

The only diagram language we have presented ("Overview" slides 28-35) is for networks of processes running in parallel. The modified numbers2, integrate2 and pairs2 processes are implemented by such networks, so diagrams are part of their design spec and should be documented somewhere. We've already given you the diagrams for numbers2 and integrate2, so we have only asked for a diagram for pairs2 (from these three).

For the processes monitor, speed.control and freeze, we are only expecting implementations that are purely sequential (i.e. contain no internal PAR networks). Therefore, there is nothing to diagram: just draw these processes as shaded (or empty) boxes (or whatever shape you like). We do not draw diagrams for sequential code – programming language syntax is good enough, or should be!

Of course, should you happen to implement monitor, speed.control or freeze as a network of internal processes running in parallel, please submit the diagrams showing this. However, sequential logic is simplest for these.

The process print.streams (which we provided) has an internal PAR, but the processes set up are short-lived (just a single channel input) and have no channel connections with each other. Its logic is mainly sequential, going parallel temporarily at the start of each loop. Such changing forms cannot be diagrammed statically. Instead, we need a movie (or, at least, a cartoon strip) showing the changing forms. For print.streams, we would need two diagrams showing its two states (and document somewhere that it continually switches between them):

    (sequential state)

                      |                                |
           in[0]      |                                |
       ------->-------|                                |
                      |                                |
                      |                                |
           in[1]      |                                |      out
       ------->-------|          print.streams         |------->-------
                      |       (col.width, delay)       |
                      |                                |
           in[2]      |                                |
       ------->-------|                                |
                      |                                |
                      |                                |

    (parallel state)

                      |                                |
           in[0]      |      -------------------       |
       ------->-------|------|                 |       |
                      |      -------------------       |
                      |                                |
           in[1]      |      -------------------       |      out
       ------->-------|------|                 |       |------->-------
                      |      -------------------       |
                      |                                |
           in[2]      |      -------------------       |
       ------->-------|------|                 |       |
                      |      -------------------       |
                      |                                |
                      |          print.streams         |
                      |       (col.width, delay)       |

The sequential state of the above is just blank (as are all sequential states). The parallel state is fairly bland: the internal processes are anonymous and unconnected (each being a single input from an external channel). So, this is not really worth doing and we haven't asked for it. Anyway, we provided this process – the diagrams we want are for new processes you are writing.

Aside: occam-pi supports concurrency that can be very dynamic. Modelling complex systems, such as biological mechanisms, often requires dynamism as living entities (represented by concurrent processes) are "born", move around some world (represented by more concurrent processes), break old connections (channels) and make new ones, combine with each other, split apart and, eventually, "die". Programming such systems is aided by drawing "cartoon strips" showing the possible sequences of network configurations in representative parts of the whole system and representative circumstances – we need these cartoon strips for initial design and subsequent implementation and maintenance. An example is shown in the "Overview" slides 71-82: we still have to talk you through those slides but, hopefully, you can see the idea.

Summary: there are no internal concurrency details for monitor, speed.control or freeze to diagram (unless you have an interesting, but unexpected by us, implementation!). We provided print.streams, so we have not asked you to diagram that (and it's not really worth doing – see above). Your implementations of pairs2 and the whole system q4 each have (or should have) a fixed internal network of sub-processes, so we have asked for one diagram each for them. The q4 process will have instances of monitor, speed.control, freeze and print.streams: these should be shown as empty (or shaded) boxes.

As said in the posting to everyone, external channels must be labelled (with the parameter names used in your code) and the directions of all channels must be indicated (by arrow-heads). Internal channels need not be labelled – but, if they are, either label them with the name of the internal channel used in your code or by the keyboard characters that cause messages to be sent along them (note: the latter is only for the channels leaving the monitor process, as shown in the exercise sheet).

Keywords: q4

Referrers: Question 24 (2012)

Question 22:

Submission reference: IN2174

For Assessment 3, will be be marked down if there is a delay from when buttons are pressed? At the moment there is a 3 line delay from then 'n' is pressed till when the numbers column resets to 0, will this be a problem?

Answer 22:

No – that's OK. See Question 14 (2010).

Keywords: q4

Question 21:

Submission reference: IN2172

I have tried to implement the same functionality from my working question 3 for freezing in question 4 by taking the whole of a multiplex? array of channels (which has the information to be printed) on through the monitor process.

I know I must be doing soemthing wrong because it doesn't compile and gives the error "left-hand side must be of type CHAN, PORT, or TIMER" twice relating to two of the lines. I've looked at it for ages and can't work out why it's saying this as the thing in question is of []CHAN INT type and if it wasn't my idea of how to implement freeze that I did in class for Q3 wouldn't work.

Here is my full code for the monitor process and q4 network:

    PROC monitor (CHAN BYTE keyboard?, CHAN INT reset.numbers!,
                  CHAN INT reset.integrate!, pairs.flip!,
		  []CHAN INT multiplex?, out!)
      BYTE keyboardBuffer:
      INITIAL BOOL running IS TRUE:
      INITIAL MOBILE []INT multiplexBuffer IS MOBILE [SIZE multiplex?]INT: 
      -- Not sure if I need to do the above?
      -- Copied it from print.streams so I could declare an array of size
      -- unknown to the compiler.
          keyboard ? keyboardBuffer
	    ...  Ed: response hidden (may change value of 'running')
          running & multiplex ? multiplexBuffer  -- <<< COMPILER ERROR HERE
	    out ! multiplexBuffer                -- <<< COMPILER ERROR HERE

Answer 21:

Sorry – I can't parse/understand the second sentence in the second paragraph of your question.

I'm assuming your multiplex channel array are the three channels the flow from the two delta processes and pairs2. Rather than route this array back through monitor, it would be simpler to route a single channel from print.streams instead – that carries all the information (needed eventually to get to the screen!).

However, routing any of these channels back through monitor is a classical mistake. It sets up a feedback loop over which you have no control of the amount of traffic (because numbers2 is always generating). If the loop gets full with every process trying to output something, deadlock results. If we design a feedback loop in our circuits (and we do this frequently), we must be able to limit the amount of traffic (as in the resettable versions of the parallel implementations of numbers and integrate, used elsewhere in this exercise).

Presumably, you are doing this so that the monitor can freeze and/or control the speed of this traffic flow. But this is dangerous (see last paragraph). Instead, get monitor to send messages to other processes to do the freezing and speed control. This can be done without setting up any feedback loops.

Your lines that don't compile:

          running & multiplex ? multiplexBuffer  -- <<< COMPILER ERROR HERE
	    out ! multiplexBuffer                -- <<< COMPILER ERROR HERE

make some sense. I think you are wanting to use as a guard the arrival of messages on all of the multiplex? channels, the catching of the messages in corresponding elements of the multiplexBuffer data array, and with the response being the forwarding of all those messages to the out! channels.

However, the input and output symbols (? and !) can only be used for receiving or sending messages from or to a single channel, not an array of channels (which is why your lines won't compile). Your second line could be implemented as follows:

	    PAR i = 0 FOR SIZE out!              -- these will
	      out[i] ! multiplexBuffer[i]        -- compile

But occam-pi does not allow the parallel replication of primitive processes as an individual guard, so there's nothing we can do to rescue the first of your two lines. There are ALT replicators in occam-pi (see "Choice" slides 109 onwards), but we've not done them yet in the course. Anyway, they do not do what you were wanting here.

However, what you should not have been wanting to do that. What you were trying to do was too complex (a single channel could have been used) and unsafe (the feedback loop in the resulting design has an uncontrolled volume of traffic and would lead to deadlock).

Keywords: q4

Referrers: Question 25 (2012)

Question 20:

Submission reference: IN2173

I am on the last stage of the assessment that asks us to implement the speed.control process.

Should we be keeping the array of 3 channels both going into and coming out of the speed.control process (and then going into print.streams), or is there a better way to do this still without altering print.streams?

Also, any general advice on what to think about when implementing speed.control is much appreciated as I am having difficulty getting my head around how to control the number of lines that will be output each second!

Answer 20:

Only one of the channels into print.streams needs controlling. You need to work out why this is true – it's important that you see this.

Once you understand the above, your speed.control process needs only one channel in and one out. Of course, a control? channel is needed as well, on which speed-up or slow-down messages arrive.

For a required speed (lines per second), work out the delay needed between lines and use the given 'pause' process. See either of the model answers ('a1.occ' or 'a2.occ') for code that sets the line speed at the start of execution (but does not let you vary it).

However, that solution has a problem. If we have the pause delay up to one second (i.e. one output line per second) and we want to speed it up, the response to a '+' keystroke will be sluggish. If we key the '+' at the start of a one second pause in the output, nothing can change in the output until that one second pause has completed.

It would be much better for the system to respond to the '+' straight away and for the output to speed up immediately. This can't be done using the given 'pause' process – a timeout guard in the ALT is needed.

Keywords: q4

Question 19:

Submission reference: IN2171

Hello, for q4 do we leave the comments at the beginning of the file in or shall we delete them?

Answer 19:

It would be nice to delete those comments (that we wrote) from your submission file – lets us get to your code quicker (and saves paper if we print). But we haven't asked for this, so it's perfectly OK to leave them.

Of course, you should include appropriate comments about your own code.

Keywords: q4

Question 18:

Submission reference: IN2170

I'm having a problem with my monitor method in Q4. If I write:

    BYTE k:
    keyboard ? k
      number ! k

obviously this won't work because of the change in data type. I've been stuck on this for the past few days, wondering if you could work out where I'm going wrong. I can't seem for the stream to continue – it just outputs nothing.

    PROC monitor (CHAN BYTE keyboard?, CHAN INT number!, integrate!)
        PRI ALT
          BYTE k:
          keyboard ? k
	    ...  (Ed: response hidden, but looks good)
          BYTE k:
          keyboard ? k
            SKIP          -- Ed: was this where you wanted: number ! k

Answer 18:

First, the monitor needed for Q4 is a process and definitely not a method! ;)

But I don't know why you want to send down an INT-carrying channel a character received from a BYTE-carrying channel? If you really wanted to do that, you would have to cast the character into an INT:

    BYTE k:
    keyboard ? k
      number ! INT k        -- send ASCII code (as an integer)

See "Basics" slide 30, the program casting.occ in your examples folder and the Q&As linked from "cast" in the keyword-index of the anon Q&As ... for further information about type casting in occam-pi.

However, I'm sure you don't want to do this (and you certainly don't need to).

The code you posted (outlined in the question above) shows that you also have some misunderstanding about the ALT (or PRI ALT). You have two guards that are the same! This means: wait for the guard to become ready, when one becomes ready both become ready (because they are the same), the second guard will never be chosen (because it is listed after another guard that's ready in a PRI ALT), so execute the first guard and the process it is defending. Again, I'm sure that's not what you intended.

The monitor process does not need an ALT (or PRI ALT). All it has to do is wait for something to arrive on its keyboard? channel and respond (as you are doing in the response I hid in the code in your question).

Hope this helps.

Keywords: q4 , cast

Question 17:

Submission reference: IN2169

I am currently on the speed.control part of my Q4.

I have initialised delay and have set it so that each button (+ and -) changes it how they should (I don't want to give too much away - if you need to look at my code, I can email it).

What happens is that it's SUPPOSED to start at 32 lines/sec. However, for reasons unknown to me, it starts at 16 lines/sec. Here's what happens if I press +/-:

    Starts at 16 lines/sec
    MINUS - It stays at 16 lines/sec (as if it were at 32 lines/sec)
    MINUS - It goes to 8 lines/sec
    MINUS - It goes to 4 lines/sec
    MINUS - It goes to 2 lines/sec
    MINUS - It goes to 1 line/sec
    PLUS - 2 lines/sec
    PLUS - 4 lines/sec
    PLUS - 8 lines/sec
    PLUS - 16 lines/sec
    PLUS - Stays at 16 lines/sec
    PLUS - Stays at 16 lines/sec

I have not yet implemented the BELL part of it, so I tested PLUS out by constantly spamming it when I was at my 16 lines/sec. Eventually, it gets to something ridiculous like 1000 lines/sec and actually does change to it, so it goes from 16 to 1000 if I hit + the right amount of times. I can not actually MINUSfrom there.

Where could I be going wrong in my code for this to happen? I know that I haven't implemented BELL yet, but I can't imagine not having that would stop my code from coming out at 32, 64, 128 etc lines/sec.

Answer 17:

Thank you for mailing me your code separately. I hope my reply was helpful.

For the others, a common mistake was being made (though this doesn't explain all the bad behaviour described, but is probably one of the causes). This mistake was placing the speed control process between print.streams and the external screen! channel. If you do this and delay (by the computed amount) every BYTE that passes, it is controlling characters (not lines) per second. If the average line length were 60 characters, then the lines per second being managed would be 60 times slower than intended.

A quick fix is only to do the pause when an end-of-line ('*c') goes past! However, there is a more efficient (and simpler) way.

Keywords: q4

Question 16:

Submission reference: IN2168

What is the exact syntax for outputting BELL along the error channel? I am simply writing:

    error ! BELL

and getting an "I/O list item 1 does not match protocol" compile error.

Answer 16:

That compiler error message is generated if BELL has a type that is different from that carried by the error! channel.

The include directive:

    #INCLUDE "course.module"

in the program file makes available lots of things, including BELL (which is defined as a BYTE constant with VALue 7, the ASCII code for bell). So long as you haven't re-declared BELL with another type in your own code following that directive, it has type BYTE.

How is the error! channel declared, somewhere above your line that doesn't compile? It should be a "CHAN BYTE error!" parameter. If it is, then your line will compile. Honest!

For the code to execute correctly, that "CHAN BYTE error!" parameter must be connected to the second output channel parameter of the main q4 process (also called error! in your starter code file, q4.occ). At least, the ASCII code in BELL will be delivered to the terminal window running your program. So long as that terminal window is configured to react to that code (e.g. by pinging or flashing the screen or both, as does the occPlug window), then all will be well.

Beware that some older releases of the Transterpreter required the error! to be flushed, in the same way as needed by the screen! channel. The current Windows version (20110201.1855) does not have that requirement.

Correct (Unix) behaviour for the standard error channel is that anything sent there is delivered immediately to the terminal window. For the standard screen channel, characters are buffered until either an end-of-line ('*c') or flush (FLUSH) is received, or the buffer becomes full: when any of these things happen, the buffer is flushed to the terminal window.

Keywords: q4 , flush

Valid CSS!

Valid XHTML 1.0!

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Last modified Mon May 20 13:50:21 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.