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 55:

Submission reference: IN2398

Consider the following code fragment.

    a ! 42
    b ! 43
      a ? x
	b ? y
      b ? x
	a ? y

Assuming the channels and variables have compatible (INT) types, what values are (or might be) held by x and y at the end of executing this code?

Although this question is not worth of many marks but I have been stuck with this.. for a while. I am not sure if I am over complicating this or not but I would answer something like "this is depending on what the computer picks (as ALT is nondeterministic) x and y will either be 42 and 43 or 43 and 42."

However, after having a second thought we do not know where a and b outputting to; are they outputting to each other? if it is then it may cause a deadlock? (another thing that I am not sure about)

Could you guide me through this please, I find it very difficult to answer this.

Answer 55:

Your first answer is correct (either 42 and 43 or 43 and 42). In practice, the second scenario you describe would be illegal in occam: if 'a' and 'b' are connected to each other, then 'a?' and 'a!' must refer to different channels, which is not allowed (aliasing essentially). The fact that the question is only worth a single mark (from the 2011 main paper) hints that you shouldn't spend more than 3 minutes on it.

Question 54:

Submission reference: IN2363

Is the following code correct?

    PROC monitor.2 ([]CHAN INT in?, ...)
      [SIZE in?]BOOL ok:

Answer 54:

Good question! Sadly, the answer is (currently) no.

Classical occam, being targetted originally at embedded applications (which have finite non-expandable memory resources), was designed to enable the amount of memory needed by an application to be decided before the code was embedded in the target machine (i.e. at compile-time). This was to ensure that the application could not run out of memory at run-time (which would mean, possibly literally, a crash). A design constraint, therefore, was that arrays could only be declared with sizes known at compile time.

Your code is trying to declare an array with the (unspecified) size of an array parameter. Any sized array may be passed, so the compiler cannot determine a specific size and the declaration is, therefore, rejected.

occam-pi does support arrays whose size in not known at compile-time but, we're afraid, the syntax for this is different (and more complex) than the syntax for classical array declarations. This is because run-time sized arrays are supported only for mobile arrays (see slide 14 of "Mobiles etc."). Your declaration needs to be:

    PROC monitor.2 ([]CHAN INT in?, ...)

See the print.streams process declared in your starter files for exercises 3 and 4 (i.e. q3.occ and q4.occ) for a similar example of this.

Once declared as above, the mobile array is used with the same syntax for accessing its elements as the classical pre-sized arrays. It is our intention to rationalise the design of occam-pi (soon) so that mobile arrays and classical arrays are merged into one concept – so that the (very natural) declaration you tried is correct and the complex one above is abolished!

Note: mobility, as presented in the "Mobiles" slides, is not an examinable part of this module. Only some of its slides on barriers (154-161 and 165) are part of the presented material that is examinable (as noted in the Week 11 box of the Moodle page for this course).

Keywords: arrays , mobiles

Question 53:

Submission reference: IN2357

I'm reading the "Choice" slides, slide 99, but I'm struggling to understand:

"By only allowing input guards, only one process is ever involved in any choice (i.e. if one process is ALTing, no process communicating with it can be ALTing)."

Can you explain this in a bit more detail?

Answer 53:

There's not much more to say ... but let's talk it through ...

The network in "Choice" slide 99 shows two processes communicating with each other by ALTing over the same two channels (a and b). Each ALT contains an input guard and an output guard. One decision has to be made – namely, which communication (over a or over b) will take place? Both processes must make this decision and they must make the same decision, which is what makes this expensive to implement.

But output guards are not allowed (currently) in occam-pi. Therefore, if one process is making a choice (ALTing) and that choice involves a channel, that involvement must be an offer to input from that channel. The process at the other end of that channel is only able, of course, to output to that channel – which it cannot be doing as part of an ALT, so it cannot be making a choice! Therefore, it cannot be involved in the choice being made by the first process.

Similarly, processes at the other end of all channels involved in the ALT of the first process cannot be involved in that choice.

The only other possible guards in the ALT of the first process are timeouts and SKIPs, none of which involve other proesses.

Therefore, if one process is making a choice, no other process is making a choice that impacts on the first choice – i.e. only one process is ever involved in deciding any individual choice. This makes ALTs inexpensive to implement, which is why output guards are (currently) not allowed!

Keywords: alt , choice

Question 52:

Submission reference: IN2315

How much commenting should we put in our code for Life on Mars?

Answer 52:

See Question 30 (2001) for the kinds of comment that should not be made!

Otherwise, you should summarise the purpose of each program entity (e.g. PROC or PROTOCOL) in comments just above its header. Ideally, this should conform to the syntax for occamDoc documentation used in, for example, your q4.occ and q7.occ starter codes and PROC draw.hit.line in the mars-sim.occ file. However, free-format comments will be fine.

In the body of a PROC, 'clever' code must be explained – anything whose purpose would not be obvious to a reader familiar, in this context, with occam-pi. For example, if there is special code to eliminate a danger of deadlock but not otherwise contributing to the purpose documented above the header, you must explain why it's there and how it does its job. It's essential to make your code understandable to readers. A base reason would be that they might be marking it! But one of those readers might be you in a few weeks time and, just because you understood it once, this does not mean you will understand it in the future. Obscure code is, in practice, worthless ... regardless of whether it works or is efficient. Obscure code cannot be maintained. Code that cannot be maintained will be thrown away.

Diagrams are an important part of the documentation of occam-pi systems. Remember to submit a process network diagram (or diagrams) if you have used concurrency in your robot.control logic. This is needed even for networks that are temporary (e.g. for the duration of a turn, move, find or deploy), but not if the concurrency is very short-lived (e.g. a parallel input/output). Diagrams for temporary networks should be enclosed in a box labelled by the PROC that sets it up (with all its external channels) and some text (or number scheme) that indicates when it is set up and for how long it lasts.

Keywords: mars , comments , diagrams

Question 51:

Submission reference: IN2297

I'm currently stuck on Task 3 - finding the blobs.

Everything seems to work fine apart from one little thing - the bearings given are SOMETIMES incorrect.

... (Ed: rest of question hidden, as it gives too much away.)

Do you think you'd be able to identify what the problem may be?

Answer 51:

From your description (not shown in the question), your robot.control inputs from the camera? channel (seeking a BLOB with the required colour) only when the robot is stationary. That seems reasonable: you are trying to get a bearing on the BLOB and do not want to get an observation that happened whilst the robot was turning.

Unfortunately, you are receiving BLOB data observed by the camera during the preceding turn! During the turn, BLOBs may come into the field of view of the camera and the image processing software will send processed BLOB data (including their bearings at the time of observation) towards your robot.control process. Since no inputs are taken from camera? during this turn, that BLOB data is not lost (this being occam-pi) but held in buffers for delivery whenever robot.control does decide to take them. When your robot finishes its turn and inputs from the camera?, stale BLOB data will be seen. This is why the bearing information you are sending back to Mission Control is often wrong.

A real-time system must always make best efforts to take data from its sensors whenever available, even it it does not need (or has no time) to process them. If any of that data is buffered for later processing, care must be taken not to use that buffered data if logic requires that only fresh data is relevant.

For the robot.control component on Life on Mars, this means taking camera data and hazard data at all times, even when turning and moving. When turning or moving, the camera data can be discarded but the hazard data, of course, must be processed. Motor feedback data only happens when turning or moving, so can probably be ignored at other times (to be safe, though, it should be still be monitored). Ideally, the opr.req? channel from Mission Control should also always be monitored (for emergency or cancel messages, though this will not happen in this assessment scenario).

To monitor external inputs at all times, an elegant solution is to have monitor processes running in parallel all the time. Alternatively, if your code is sequential, use ALTs to process inputs from all sources, even when your primary focus is on just one (or two) of them.

Keywords: mars

Question 50:

Submission reference: IN2300

For the Life on Mars assessment, are we allowed to changed some of the robot.control channels to SHARED?

Answer 50:

Yes. But you will have to work hard on the mars-sim.occ file to let it compile. The channel that gets plugged into your robot.control needs to be declared with its writing-end SHARED. Now, mars-sim.occ caters for multiple robots on mars and provides arrays of opr.req and opr.resp channels back to its (simulated) mission.control process – for your assessment, the number of robots is set to 1. Unfortunately, the occam-pi compiler does not currently allow arrays of channels to be declared with SHARED ends – if you need them, you will need to investigate MOBILE CHAN TYPEs (from "Mobiles" slides 24 onwards, which have not been presented in this module and are not examinable). A simpler solution, however, would be to modify mission.control to a single pair of opr.req / opr.resp channel-ends whose other end (at the robots on mars) is SHARED.

If you do this, you will need to submit your revised mars-sim.occ file (along with mars-main.occ) plus adequate documentation (in both files) explaining your changes and the reason(s) why you made them. This is a lot of work.

Why do you want to make some of the robot.control channels SHARED? I know no good reason. Please read Question 49 (2012), where the questioner was having a technical problem for which a SHARED channel was raised as a possible solution ... but the real problem was some weak software engineering (low cohesion: putting too much functionality into a PROC) and over-engineering (result channels instead of reference parameters to return results). Maybe your problem is similar?

Keywords: mars , shared-channel

Question 49:

Submission reference: IN2295

I have a hazard.monitor process as suggested in the answer to Question 59 (2011) and that seems to be working.

For Task 3 of the mars assessment, I'm trying further parallelism. I have a turn.robot process in parallel with a find.blob, with a cancel channel between them. If find.blob finds the specified blob, it sends a cancel to turn.robot which stops its turn. I have a result process that receives results from both turn.robot (how much it turned) and find.blob (if it found the specified blob and, if so, the blob itself).

However, turn.robot is also used to respond to a turn command and has to send to opr.resp!. My result process also wants to send to opr.resp!. But the opr.resp! parameter given to robot.control is not SHARED, so I cannot run turn.robot, find.blob and result in parallel. If I put result in sequence and after running the other two in parallel, it compiles but, of course, gets stuck as soon as turn.robot and find.blob try to report their results to result which hasn't yet started!

Is there any way out of this impasse, please?

Answer 49:

You have two problems.

First, see Question 55 (2011), the paragraph in the answer starting: "From the software engineering principle of cohesion ...". That was talking about a move process, but it applies to turn as well. Task 4 will need lots of turns and you'll want to reuse your turn.robot ... but you won't want it reporting on opr.resp! each time! Do what it says there: remove the opr.resp! parameter from turn.robot and promote your local variable that is accumulating the ticks to a reference parameter. Then, whoever invokes turn.robot will get the ticks it found (when turn.robot finishes) and can report, or not, to opr.resp! as needed. Now, the need for its ticks-reporting channel has gone, so get rid of it.

In general, an initialisation channel that just delivers one value to a process should be replaced with a VAL parameter with that value. Similarly, a reporting channel that delivers only one final report should be replaced by a reference parameter to which the report value is assigned.

[Side-note: check out the answer to Question 58 (2010) for the concept of RESULT parameters. We've not presented them in the course, so they are not examinable. However, they are very simple to understand and use and give added safety (against programming error) and elegance to the recommendation in the second sentence of the preceding paragraph.]

So, get rid also of the reporting channels in find.blob. Replace them by promoting the local variables holding the report values (whether it found a blob with the specified colour and, if so, the blob itself) to reference (or RESULT) parameters. Now, like the changed turn.robot, it has no need to communicate with your result process via a channel and no need, therefore, for that result process to be running in parallel with it.

Now, put result in sequence and after running the other two in parallel, declaring and passing variables for ticks, found-the-blob and blob (as needed by result and the other two). This time, it compiles and result gets the information it needs. Indeed, now that result no longer need to input result data, its code should be trivial enough to write in-line (without a PROC).

Don't forget that, with this modified turn.robot, the code for responding to a turn command (from opr.req?) needs a little extra.

Things should work better now.

You're not there yet though. If a blob is sought that is not in vision range even after a full turn, does your find.blob keep waiting? If so, your response to a find command will never finish – the robot will do a complete turn and nothing else will happen.

Just as your find.blob cancels turn.robot if it finds a blob, so your turn.robot should cancel find.blob if it completes a full turn (plus a couple of seconds to allow for camera processing of the image in its final position). But there's deadlock lurking if they both commit to cancelling each other around the same time – this needs to be avoided. There is a simple solution, but we leave it to you to find.

Keywords: mars , shared-channel

Referrers: Question 50 (2012)

Question 48:

Submission reference: IN2294

I'm trying to do Task 3 of Life on Mars, but I'm having issues with the timeout - specifically, the actual time it waits is often absurdly long, sometimes minutes.

    tim ? t
      tim ? AFTER t PLUS CAMERA.SCAN.TIME     -- 2 seconds
        ...  turn robot 90 degrees and increment a 'count'
      BLOB b:
      camera ? b
        ...  if 'b' has the sought colour, set 'searching' FALSE & report to mission control

It doesn't matter whether there are any blobs in view or not, and recompiling or rerunning doesn't produce consistent results.

Answer 48:

You don't show the enclosing loop. From what you show, I'm guessing something like:

    WHILE searching AND (count < 4)
        tim ? t
        PRI ALT
          tim ? AFTER t PLUS CAMERA.SCAN.TIME     -- 2 seconds
	    ...  turn robot 90 degrees and increment a 'count'
          BLOB b:
          camera ? b
	    ...  if 'b' has the sought colour, set 'searching' FALSE & report to mission control

Now, suppose a BLOB is reported on camera but not with the sought colour; then execution goes round the loop and the timeout is reset for another 2 seconds. The 'mandelbot' rock formations are reported (by the image processing processes running in parallel with your robot.control) as potential BLOBs down the camera channel, but will have different colours to the BLOBs sought by mission control. Further, so long as a potential blob is in view, it will continue to be reported down camera at least once every CAMERA.SCAN.TIME. In practice, CAMERA.SCAN.TIME is a bit generous and blobs may be reported a little more often than that.

So, if the sought BLOB is not in vision but something else is and that something gets sent down camera before your code times out, the potential blob is ignored and your timeout is reset for 2 more seconds. This can carry on indefinitely, the timeout never happens and your robot in never told to turn!

See "Choice" slide 46 for the right way to set the timeout times.

Keywords: mars , timers

Question 47:

Submission reference: IN2273


I am trying really hard to implement the move process for the mars assignment and have got stuck with what is happening in my code...

I've been trying to follow advice in Question 55 (2011).

I have implemented a nested replicated ALT (as suggested) and believe before my loop gets to run I check that you can move by looking at the hazard array (as suggested) but for some reason my code gives unexpected behaviour:

When you first move it will move up till a hazard is detected, eg move 1000 moves 180 and stops. Subsequently, I would have thought telling it to move again would cause it to not move forward anymore (as it would check the sensors, which would discover a hazard and never allow the "moving" Boolean to be set TRUE and thus the robot not move). However, subsequent calls to move always allow the robot to move but with smaller amounts. You can keep repeating this until the robot moves all the way through a hazard which is clearly wrong.

I know this must be something to do with the way I am polling the hazard channels in my first bit (where I check before I drive) but I can't see how I would structure this to not happen. The Hazards are prioritized over the SKIP guard so surely, if a hazard exists, the robot shouldn't move!

My code:

    PROC robot.move (...)
      ...  (Ed: code hidden)

Answer 47:

A hint to your problem is the first sentence in the last paragraph of your question. As we've said before, polling is usually the wrong thing to do. It certainly is wrong here. For one thing, you poll all four hazard channels and take a response from only one of them - or SKIP if none were sending. So, one might be reporting a zero level and the other three screaming 10 (DANGER!) ... your poll may take the one reporting zero, ignore the other three and issue the drive.forward command to the motor.

However, the Mars web page says:

"You will receive communications on these channels only when and if the value changes."

So if the vehicle is stationary, nothing will be coming down those hazard warning channels – even if you are facing a brick wall! Polling the hazard channels will see nothing.

The hazard warnings would have been sent as your robot was approaching the obstacle. Your robot control should have remembered the warnings.

As the answer to Question 55 (2011) says, the simplest way to remember is to have a dedicated process to monitor the hazard channels at all times and maintain the information on current hazard levels. This runs in parallel with the process doing the move. The latter can check hazard levels before starting the motors by asking the former.

The move process could continue to do this as it moves, by asking after each click motor.feedback. This is not very efficient and may miss a hazard warning if motor feedback signals were ever delayed for some reason. Better would be to ask the hazard process to let the move process know if a hazard (significant to its direction of movement) has been spotted – then the move process just ALTs between a warning channel (from the hazard process) and the motor feedback channel. If the move completes with no hazard warning, the move process needs to cancel its request to the hazard process. Careful: there is a danger of deadlock here that must be avoided.

On the other hand, if your control logic is serial, the move PROC must ALT between motor feedback and all hazard channels. But it must initially know the current hazard levels and, when finished, return them. Clearly, this must be through a reference data parameter.

Final thought ... if using serial logic ... does your turn PROC need to do the same?

Keywords: mars

Question 46:

Submission reference: IN2230

Just looking to clarify whether we need network diagrams or not? If so, for what processes. Thanks.

Answer 46:

Information on this has been added to the "Assessment 4 (Dining Philosophers Animation)" part of the Assessments box on the Moodle page.

In general, a network diagram is needed for any PAR network in the system (e.g. the college itself and the system-as-a-whole). If you have any animation processes, they may be directly in the system-as-a-whole or may be grouped into their own enclosing process (with diagram), with only the group-icon in the system-as-a-whole.

However, if any network in your system has the same diagram as any shown in "Applying" slides 60, 65, 66, 70 and 71, just refer to them in comments associated with the relevant PAR. It's pointless reproducing diagrams from the slides, so we're not asking you to do that.

Keywords: q7

Question 45:

Submission reference: IN2225

I got the occam compiler (Windows, Transterpreter\bin\occ21.exe) to crash, without any error output. The code, after relentlessly pruning out lines that didn't cause it to crash, is:

        BYTE x:

    PROC yum (VAL BYTE a)

    PROC black.magic (STRUCT record)
      VAL INT k IS 0:
      yum (record[x] + k)

    PROC pure.evil ()
      [1]STRUCT records:
      SEQ i=0 FOR 1
        records[0] := 0

Switching the order of the last two procs, changing the replicated SEQ into a normal SEQ, changing the records array into a single record, or using a literal 0 instead of k will avoid the crash. Of course, fixing the syntax error will also prevent the crash.

Not a question, perhaps a better one would be 'where do I submit this?'

Answer 45:

Although the compiler dies horribly, it does output an error. A feature of the Transterpreter is that you don't always get to see the error output before the crash happens — effect of buffered outputs. The specific error is a type error though; in this case there are two, the second of which was blowing up the compiler (basically it was deferencing a null-pointer when trying to find the name of the parameter involved, which of course didn't exist in this context).

This now produces some more sensible errors:

    Warning-occ21-bug1.occ(7)- parameter a is not used

        :PROC black.magic (STRUCT record)
        :  VAL INT k IS 0:
      13:  yum (record[x] + k)
        :PROC pure.evil ()
        :  [1]STRUCT records:
    Error-occ21-bug1.occ(13)- operands have different types for operator "+"

        :PROC pure.evil ()
        :  [1]STRUCT records:
        :  SEQ i=0 FOR 1
      19:    records[0] := 0
    Error-occ21-bug1.occ(19)- type mismatch

For future reference, the place to send error reports (and general compiler bugs) is kroc-bugs@kent.ac.uk; this is fairly well documented in the KRoC release, but less so in the Transterpreter (at least as you see it — googling for "occam compiler bug reporting" produces the relevant address!). Thanks for spotting this bug in any case (which I've now fixed).

Keywords: compiling

Question 44:

Submission reference: IN2204

With q7, can we assume that there will only ever by 5 philosophers? Or will marks be deducted if we implement it in this way

Answer 44:

It depends. For the purposes of doing animation type displays (even at the level of the basic/model solution) then it's a reasonable assumption. Trying to make the display logic cater for arbitrary numbers of philosophers and forks will be difficult. However, avoid having code which looks like:

    VAL INT PHIL.0.Y IS 2:
    VAL INT PHIL.1.Y IS 3:
    VAL INT PHIL.2.Y IS 4:

      id = 0
        ...  stuff involving PHIL.0.Y
      id = 1
        ...  almost the same stuff involving PHIL.1.Y

which is something we're likely to deduct marks for (duplicated code) — better to use arrays of constants and index, e.g.:

    VAL []INT PHIL.Y IS [2,3,4]:

    ...  stuff involving PHIL.Y[id]

Keywords: q7

Question 43:

Submission reference: IN2208

I have been trying for a while to try and use the random function to generate random eating values. I cannot see an issue with my code, but strangely when running it will run for a short time and then it will just seem to freeze. My code for this section is as follows.

    ...  [snip code]

    PROC philosopher (VAL INT id, seed, CHAN BOOL left!, right!, down!, up!,
                      SHARED CHAN P.PHIL report!)
      INITIAL INT t.seed IS seed:
      INITIAL INT e.seed IS seed:
      INT pID:
      INT thinkMax:
      INT eatMax:

      INT thinkTime:
      INT eatTime:
        thinkMax := max.think.time MINUS min.think.time
        eatMax := max.eat.time MINUS min.eat.time
        pID := 42*id 
        e.seed := e.seed PLUS pID
        t.seed := t.seed PLUS pID
        WHILE TRUE
            eatTime, e.seed := random(eatMax, e.seed)
            thinkTime, t.seed := random(thinkMax, t.seed)

            eatTime := eatTime + min.eat.time
            thinkTime := thinkTime + min.think.time
            ...  [snip code]
            pause(thinkTime * second)
            ...  [snip code]
            pause(eatTime * second)

According to my understanding, this should take the seed (which is the seed generated in PROC q7) add to this pID and then use this seed to generate a value between 0 and (max-min) for that particular process. It should add the minimum value to this thus giving me a range between the maximum and minimum values.

This then is passed to pause (which is taken from exercise q4) as its value * second (which is declared at the top of the file we were given as VAL INT second IS 1000000).

The issue seems to be with the random value generated as I changed eatTime and thinkTime to actual int values and it seems to work fine.

If my understanding is incorrect could you tell me where i'm going wrong and if my understanding is correct help me figure out why it isn't working as it should. I've been staring at this for two days now.

Answer 43:

The code you have there looks sensible, and yes, random does behave in mostly the way you think. However, the two seed values here (e.seed and t.seed) will be the same: they start the same and go through random() in the same way together. You only really need one random seed here, rather than two. That though should not produce any odd behaviours; if the '.think.time' and '.eat.time' constants are the same, then the thinking and eating delays will be the same, which may look a little odd in the display, but shouldn't produce overly long pauses. Check the values for these though, which should sensibly be expressed in seconds.

It's possible that you have some sort of deadlock, which is only arising a result of particular timings of interaction (more likely to happen with random timeouts than without). Check the usage of CLAIM blocks in particular, the only thing inside these should be outputs on the particular shared channel (in this program) — trying to do other things may lead to deadlocks as other processes won't be able to claim that shared channel at the same time.

Failing that, mail your code to your seminar leader to have a quick look for obvious errors.

Keywords: q7 , random

Question 42:

Submission reference: IN2213

I am trying to use occade in the transterpreter (on Mac), simply trying to add a background:

    SHARED OCCADE! occade:
    INITIAL OCCADE.PARAMS params IS occade.default.params:

      params[width] := 640
      params[height] := 480
      occade.start (occade, params, "Dining Philosophers")
      occade.load.playfield (occade, "images/bg.png", 0, 0)

That code should work fine, the file does exist. I have also tried bitmap. The error is that the image does not get loaded and it goes into a deadlock. Here is the error that is shown on the terminal:

    ...  [snip screenshot]

Any idea what could be wrong? Thanks.

Answer 42:

Your error output refers to rasterio.occ:48. This is what happens when occade (or, rather, the raster library) can't handle the file-type. At a guess, this Transterpreter instance has been compiled without libpng support, so cannot load PNG images. Try converting the file to a PPM instead and see if that works. Other things to check (assuming it's not that) are relative vs. absolute path to the file, display size (image size must match) and depth.

Keywords: occade , q7

Question 41:

Submission reference: IN2209

Every time I try to compile my code I get the following messsage:

    running: q7.tbc
    S:\courses\co538\transterpreter\bin\tvm.exe: could not open file: q7.tbc!
      Usage: S:\courses\co538\transterpreter\bin\tvm.exe BYTECODEFILE [MEMSIZE]

        BYTEFILE must be a valid Tranterpreter bytecode file.
        If MEMSIZE is specified, it is the the workspace size of the program;
        if not specified it will be computed automatically.
    q7.tbc exited with error code: 1

Is there any way to fix it?

Answer 41:

The main issue is that you're trying to run something which has not yet been compiled — the former depends on the latter in this case! In the TVM there should be two buttons, one which runs the program (and is producing the error you're seeing), the other which tries to compile it, turning your source "q7.occ" into the TVM bytecode file "q7.tbc". If it failed to compile, for whatever reason, the problem is there, but you can paste those errors in (if any) and we can try and help :-).

Keywords: transterpreter

Question 40:

Submission reference: IN2206

My output is behaving very strangely. When I run the program, the output comes in chunks and all squashed inline, rather than one by one, line by line. I can't work out if it's to do with the following code in my q7 process:

    SHARED ! CHAN REPORT report!
      SEQ i = 0 FOR n.philosophers
        secure.college (report!)
      display (report?,screen!)

however if I change this to:


then I get an error in the fork process saying that I need to claim a channel before I use it. However, it is being claimed like it is in other places in my program, on the line:

    CLAIM REPORT ! fork.down;id  

    ...  [snip code]

    PROC display (CHAN REPORT in?, CHAN BYTE screen!)  

      ...  [snip code]

        out.string ("stuff", 0, screen!)
        cursor.down (1, screen!)
        --screen ! FLUSH

      ...  [snip more code]

Answer 40:

The reason for the strange output is because you have commented out the 'FLUSH' outputs that force the program's output buffer to empty. The procedure 'cursor.down' will emit an escape sequence that moves the cursor, but isn't guaranteed to flush the output. The normal way to flush the output is to write out a newline sequence (the output is line-buffered), e.g.:

    out.string ("*c*n", 0, screen!)

The replicated SEQ around the call to 'secure.college' is redundant — it doesn't make sense to loop over n.philosophers iterations of the college. Running the 'secure.college' in parallel with the 'display' process is sufficient. The error that you get as a result, however, looks unrelated. Looking at the code you pasted, the error is that 'REPORT' is written like that, meaning the "REPORT" protocol, and not the 'report' channel (lowercase). Outputs to the 'report' channel here should look similar to elsewhere (e.g. in the philosopher code).

Keywords: q7 , animation

Question 39:

Submission reference: IN2200

I am just wondering what the right way to implement the animation is. So far, I have already tried using the display process already coded, but instead of outputting lines of text, lines of characters forming a shape of some sort, however this always seems to deadlock after one step. It however, does not deadlock when running the original display process.

Answer 39:

This suggests there is a problem with the modified display process. Without seeing the code it's fairly hard to diagnose, but do check, line-for-line, that the display process is doing what you think it ought to be. Common causes of this sort of deadlock are deleting some necessary loop (i.e. the display process handles one message then deadlocks), or dependencies added internally, e.g. with loops and delays for the animation, that break the overall operation of the system. If the problem isn't obvious, I'd recommend asking your seminar leader, who'll be able to offer some rapid advice on what's wrong and where.

In the case of complex animations (e.g. sprites moving around the screen), the logic that moves such things step-by-step should be separate to the main "display" process (i.e. as parallel processes between the philosophers/forks/etc. and display).

Keywords: q7 , animation

Question 38:

Submission reference: IN2198

I'm having an issue with the idea of CLAIM in the processes. The problem I'm having is that when I try and add CLAIM to the shared channel, I'm getting incorrect indentation. I've tried shifting the indentation but this creates a different error shown below. I've been reading and re-reading the slides, and I can't see where I'm going wrong, nor what is actually correct.

      ...  (Ed: other guards hidden)
      BOOL any:
      left ? any       
        CLAIM report!
          report ! fork.up;id
        left ? any     <<-- incorrect indentation
          CLAIM report!
            report ! fork.down;id

IF I have the following code, it throws an error that – "must CLAIM 'report?' before using channels":

    ...  (Ed: code hidden)

Answer 38:

A CLAIM and its indented code block is a process. The second input line from the left channel is a process. They are listed at the same level of indentation as the response to an ALT guard (the first input line from the left channel). Always, when there are two or more processes to run, we must say whether they are to be run in SEQuence or in PARallel. Here, they need to be in SEQuence. The second CLAIM and its indented code block is also a process and needs to be the third element of that sequence – so it must be at the same level of indentation. Therefore, there is a missing SEQ and the code must be laid out to define what's in that SEQuence:

      ...  (Ed: other guards hidden)
      BOOL any:
      left ? any       
          CLAIM report!             -- first process of the SEQ
            report ! fork.up; id
          left ? any                -- second process of the SEQ
          CLAIM report!             -- third process of the SEQ
            report ! fork.down; id

If you follow the "USEFUL NOTE" in the answer to Question 37 (2012), the above can be shortened to:

      ...  (Ed: other guards hidden)
      BOOL any:
      left ? any       
          CLAIM report ! fork.up; id
          left ? any
          CLAIM report ! fork.down; id

Re. the last part of your question, I can see nothing wrong with the code you sent ... and neither did the compiler when I tried it. Are you sure you included the right bit of code?

Keywords: q7 , shared-channel

Question 37:

Submission reference: IN2197

I have a shared channel called report which all philosophers and forks will write to. I think I have set this up correctly and it all compiles ... but when I run the program I immediately get:

    program failed, state= e, eflags = 00000000
    exited with error code: 1

referring to line 108 which is the line in my secure.college process where fork would be writing to its report channel (the last line).

I have not implemented anything further with forks actually writing to the report channel, yet in the fork process it is flagged yellow saying it is currently unused. I have only implemented the reporting for philosophers so far as I wanted to test if that worked before I added forks and security guards.

Here is the code for my almost unchanged reporting.college process.

    PROC reporting.college (SHARED CHAN REPORT report!)
      ... (Ed: code body hidden)

How do I go about finding out why this is happening?

Answer 37:

As always, the best way to debug code is to read it. However, shared channels are a new concept and I hid the relevant code when editing the question (to allow general viewing) ... so let's talk through what you sent.

Your reporting.college creates (in parallel) all the college processes and plugs all of them into its SHARED report channel-end parameter. However, the college processes cannot be declaring their report channel-end parameters as being SHARED, so they can't directly be plugged in. I can deduce this because, before instancing each college process, reporting.college first CLAIMs the report channel-end. This gives exclusive use of the report channel-end and the college process may now be instanced (exclusive use means the channel-end is no longer shared). Thus, your reporting.college compiles.

But what happens when it runs? Each process in the PAR competes with all other processes in the PAR to CLAIM the report channel-end. One of them wins and the others are blocked (and wait in a queue). However, the winning process then executes its college process in the CLAIM block ... that process never ends ... so the CLAIM is never released. That means no other college process ever starts ... the processes starting them are all queued up trying make their CLAIM. As soon as the winning process tries to communicate with any other college process, it blocks (because that other college process isn't there). So, all college processes are blocked. The display process is blocked, waiting to hear from any college process. Deadlock (apologies for the poor error message from the Transterpreter – the kroc run-time actually reports deadlock).

GENERAL PRINCIPLE: when you share a resource, it's necessary not to grab it until you need it and not to hang on to it afterwards ... and, certainly, not for ever!

FIX: get rid of those CLAIMs on the report channel-end within reporting.college. Now look at the last two sentences in the answer to Question 36 (2012). See also Question 29 (2012) for a similar problem.

USEFUL NOTE: here's some information that's not currently in the "Shared-etc" slides. Slide 10 shows a CLAIM on an output channel and a note that, in the CLAIM body (indented from the CLAIM line), we may use that output channel as many times as you like. However, we often only want to use it once - e.g.

    CLAIM report!
      report ! hungry

In this case, the code may be written in one line:

    CLAIM report ! hungry

which makes the code look less busy and easier to read.

Keywords: q7 , shared-channel

Referrers: Question 38 (2012)

Question 36:

Submission reference: IN2196

I'm trying to implement a variant PROTOCOL called report and part of the design of that protocol is that philosophers, forks and the security guard will need to report on it. But when I try to do this using a similar method to how I did previously with an array of 11 channels in the secure.college process, I get an error:

    xxx.occ(99)- parallel outputs on channel `report'

My code surrounding the error reads:

    PROC secure.college (CHAN REPORT report!)
      ...  (Ed: code body hidden)

Is this because I need to make it a shared channel? If so how do i go about doing this?

Answer 36:

Yep. Just declare the report! channel as being SHARED. Otherwise, the normal occam rules against parallel outputs to the same channel apply and the compiler, correctly, complains. Your process header should be ("Shared-etc" slide 7):

    PROC secure.college (SHARED CHAN REPORT report!)

Your code body for the above will now compile (with parallel processes outputting to the same, now explicitly shared, channel). At least, it will compile so long as your individual college processes (phil, fork and security) also declare their report! channels as being SHARED. Of course, those college processes will then need to CLAIM their report! before using it ("Shared-etc" slides 8-9).

Keywords: q7 , shared-channel

Referrers: Question 37 (2012)

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.