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

I'm using cursor.x.y to make my interface but I've run into a problem. cursor.x.y takes two BYTEs and my program involves general formulas that take the fork/philosopher number and use it to calculate the co-ordianates of where the cursor needs to be. Is there any way of casting an INT straight into a BYTE of the same number? For instance, of the `x co-ord' needs to be ``(2 * philosopher number) + 2'', how can I get that from being an INT to being a BYTE I can use in `cursor.x.y' ?

Answer 101:

See Question 89 (2003).

Keywords: cast

Question 102:

How do i erase a certain number of characters at the cursor, i.e.

      -- erase 2 characters
      out.string(":(", 0, screen)

Answer 102:

This is actually quite simple -- just output some spaces. e.g.

      cursor.x.y (X, Y, screen)
      out.string ("  ", 0, screen)
      cursor.x.y (some.other.X.coordinate.I.guess, Y, screen)
      out.string (":(", 0, screen)

Question 103:

I have problems with this range error:

    KROC: Range error / STOP executed (signal 4) 
    KROC: Fatal error code 1, core dumped
    Abort (core dumped)    

I have looked at the past Anonymous question pages. But none seem to be the problem. I run my program and it seems to run fine. Occasionally it crashes with the range error above. This normally happens about 10 minutes into running it, however it can sometimes occur just after 10 seconds. I'm not quite sure what else could be the problem as I think that after 10 mins of running the process that it would have excuted all of the code at least once.

Here's the list I found that I have checked against:

any suggestions of what i could do to elimate this very annoying bug ???

Answer 103:

The biggest clue as to what is going wrong is the fact the timing of the crash varies. At a guess, the error is the result of time manipulation using `+' instead of `PLUS', or other arithmetic involving `time' that does not use non-overflowing operators (TIMES, PLUS and MINUS).

As has been said in other posts, if you want more information on the error, you'll need to run with (run-time) debugging enabled. This is only supported on KRoC/Linux at the moment.

Keywords: range-error , stop

Referrers: Question 31 (2012) , Question 9 (2004) , Question 43 (2004)

Question 104:

I want to have an array of strings (which I have understood to be an array of bytes) but am unsure how to use this. Is it:


And also how would I write into a specific location, e.g. put "hello world" into index `0' in the string array?

Answer 104:

You are along the right lines with your declaration. More correctly:

    [number.of.strings][string.length]BYTE string.array:

The important thing to remember (as was covered to some extent in `q6') is that occam does not have an explicit `string' type -- they're handled using arrays of BYTEs. Thus you need to cater for `string length' separately (or use `null'-padding on the strings).

The above declaration declares an array of arrays of BYTEs. In other words, an array of fixed-size strings. If all the strings are going to be constant, declare it as a VAL array, e.g.:

    VAL [][]BYTE string.array IS ["hello world   ",
                                  "from occam    ",
                                  "but not from C"]:

Note that all the `strings' are the same-length -- the compiler will reject the declaration if this is not the case.

If you go down the `variable' route, data can be placed in the array using standard assignment, but the types must match exactly -- `[4]BYTE' and `[6]BYTE' are different types, for example. Thus assignments will often end up using array slices. See Question 44 (2002) for a comprehensive description of these. E.g.:

    [10][20]BYTE string.array:
      [string.array[0] FOR 11] := "hello world"          -- type is [11]BYTE
      [string.array[0] FROM 11] := "         "           -- pad remaining BYTEs with spaces

or this could be done as a single assignment:

      string.array[0] := "hello world         "          -- type is [20]BYTE

Keywords: arrays , strings

Referrers: Question 40 (2011) , Question 33 (2006)

Question 105:

I know you can delete from the cursor to the end of the line, from the cursor to the start of the line, the whole line, or the whole screen, but is there anyway of specifying to points to delete between?

Answer 105:

Not directly. You could, however, write a simple PROC to do this. E.g.

    PROC erase.horiz (VAL BYTE x1, x2, y, CHAN OF BYTE out)

An alternative would be to use `out.repeat'. e.g.:

      cursor.x.y (x, y, out)        -- move cursor to (x,y)
      out.repeat (' ', n, out)      -- clear n characters

Question 106:

On question 7, my philosophers pick up the forks fine but sometimes they tend to just pick up one fork and can eat and sometimes have 2 forks. I am using 3 multiplexers in total one for the philosophers, one for the forks and another to plex them two and also the security guard. I wonder if this could be affecting the output?

Answer 106:

When a philosopher is eating, they should have both forks (on the display). There are three `messages' involved in this: left-fork picked up, right-fork picked up, and philosopher eating. Due to the way the system is `wired-up', the `display' process may receive these in any order. There is a chance that the ordering will be: philosopher-eating, left-fork then right-fork. Thus, it is important to ensure that display updates involving the philosopher do not intefere with display updates involving the forks -- accidently erasing previously outputted text, for example.

What you describe sounds like an artifact of the plumbing of your system - because you have 2 levels of multiplexing of report messages to your display process. Fortunately, this is fairly easy to correct!

When a philosopher or fork or the security guard outputs a report, if that report goes directly to the display process we know that that display process will update the screen (and FLUSH!) before dealing with the next report. However, if a fork (or philosopher) report goes first to a special fork (or philosopher) multiplexing process which then forwards it on to the actual display process, all the fork (or philosopher) knows - after outputting its report - is that that first level mulitplexor has got it, not that the display process has received it! The fork process may then interact with a philosopher (who is putting the fork back on the table) before the display process has shown the fork in the hand of that philospher. It is possible for the display process to animate the philospher moving to the eating position and then to the thinking position before it animates any fork movement, :(.

The simple fix is to get the philosopher or fork process to wait for confirmation from the multiplexor process to which it is connected that that multiplexor has indeed forwarded it to the display process - before the philosopher or fork process moves on. How to do this is described in the answer to Question 76 (2003).

Keywords: q7

Referrers: Question 28 (2012)

Question 107:

What does the occam keyword `INITIAL' mean ?

Answer 107:

Note: this keyword was not presented in the lectures, so knowledge of it is not examinable. It's not needed except that it shortens and clarifies some lines of code. Please note the last line of this answer if you intend using it on the SPARC/raptor compiler.

`INITIAL' is used to declare and initialise a variable in one line. For example:

    INITIAL INT x IS 42:
    P (x)

is equivalent to:

    INT x:
      x := 42
      P (x)

Note: the above equivalence only holds in certain cases. Something that is often written is:


This creates a new variable, `x' whose value is initialised to another `x' in scope at that point. Clearly, substituting into the above equivalence doesn't work:

    INT x:
      x := x
      P (x)

... that is broken, since the original `x' has been de-scoped. The actual behaviour of `INITIAL' (for ``INITIAL INT x IS x'') is:

    INT $anon:            -- strictly illegal variable name
      $anon := x
      INT x IS $anon:     -- renaming (abbreviation)
      P (x)

On KRoC/Sparc, you need to use the `-X3' compiler flag to enable `INITIAL' declarations. This is enabled by default on KRoC/Linux.

Question 108:

I've seen that in the dining philosophers animation, when fair ALTing the status reports from the philosophers, forks and security guard, you may have three different case protocols, and have one channel going to the display proc for the philosopher, one for the forks, and one for the security guard. Our seminar leader said that semaphores should be used for the channels where more than one PROC could output at the same time (for philosophers and forks). Is it ok to use `semaphore.inc' in the course library on raptor, or do we need to produce our own implementation?

Answer 108:

[Note: this answer is no longer valid! The SEMAPHORE data type is no longer supported by the multicore run-time systems for occam-pi. The correct way to share channels is to use the SHARED channel mechanism that is now part of the language (and mentioned in the last paragraph below).]

If you wish to share channels in this way, yes, using the `semaphore.inc' provided is fine -- and encouraged. If you look at the contents of the file, you'll see that implementing your own is very much non-trivial (although you (CS) know the theory from CO501).

This file defines a `SEMAPHORE' data-type and various PROCs to manipulate the semaphore. Since usage-checking must be disabled on the shared variables, there is a substantially increased risk of program error. Mis-handling of such semaphores can cause anything from deadlock to a serious run-time error (segmentation fault of KRoC). Using lots of channels and ALTing is always a safer bet, but not as efficient or ideal.

The new occam provided in KRoC/Linux has support for SHARED channels at the language level; thus ensuring a basic safe usage (deadlock can still occur through design error, however).

Keywords: shared-channel

Question 109:

I lost my notes from the seminar where we did arranging stuff on the screen, could you tell me the commands for relocating the cursor, blanking the screen and changing text colour.

Answer 109:

The other answers under the animation keyword should be useful. In summary, though:

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

... and many others. Changing the text colour isn't entirely trivial -- there are no pre-defined PROCs to do it for you. However, here's a simple example that prints some text in bold red (before restoring the default colour/attributes):

      out.string ("*#1B[1;31m", 0, screen!)
      out.string ("Hello, bold red world!", 0, screen!)
      out.string ("*#1B[0m", 0, screen!)
      screen ! FLUSH

The various ANSI/VT100 escape codes and suchlike can be found via google. A basic, but useful, reference can be found here.

Keywords: animation

Referrers: Question 113 (2004) , Question 113 (2004)

Question 110:

This is my code for my random number generator in the philosopher PROC. To make it random should I replace my 3 second delay with seed to make it random ??

      number, seed := random.gen(end, seed)
      tim ? t
      tim ? AFTER t PLUS 3000000
      out ! thinking
      seed := (seed >> 2) + 1

Answer 110:

No -- `seed' is the random seed, not the random number. When you call `random':

    number, seed := random (n, seed)

you get a random number between 0 and `n - 1' in `number', and an updated `seed'. Thus, you should delay for `number', or some function thereof.

The code you have that modifies seed (shift-right and add one) should only be done once, and outside of any loop in the philosopher. This is used to initialise the `seed' initially -- once initialised, you never need to explicitly reset it (calls to `random' update `seed' -- by parameter and result).

Question 111:

I found a problem doing a past exam question, while trying to cast an INT into a REAL32:

    INT sum:
      out ! values[index]; (REAL32 sum) / 10

but the compiler complains:

    "Type of operand invalid for exact type conversion REAL32"

Answer 111:

The designers of occam were very precise mathematicians, amongst other things. When you cast an INT into a REAL32, you don't expect precision problems - e.g. 42 should become 42.0 precisely (and it does).

However, large INTs do not convert exactly into REAL32s ... which only use (around) 24 bits to hold the mantissa (the actual number) and the rest to hold the exponent amd sign bits. But INTs use 31 bits to hold the actual number and 1 for the sign. Now, 31 into 24 don't go! So, only the first 24 bits go over when casting and the rest are implied zeroes (how many is defined by the exponent bits). The least precision bit of those 24 bits has to be decided. That decision requires you to specify whether that's to be done by rounding (to the nearest whole 24 bits value) or truncating towards zero. In occam, you must make that specification ... so your line should have been either:

    out ! values[index]; (REAL32 ROUND sum) / 10.0


    out ! values[index]; (REAL32 TRUNC sum) / 10.0

depending on what you want. I don't know any other language (?) that is as fussy as this but the care is justified. Java/C will cast an int to a float without batting an eyelid ... does anyone know which way it decides that final bit when the number is too large ... I bet different C compilers will generate code that does different things ... may even be architecture dependent, so that the same compiler does different things on different architectures. May also be true for Java.

Of course, if your INT value is between ``-2**23'' and ``(2**23 - 1)'', then no decision about rounding-v-truncating is needed. But the occam cast is still `REAL32 ROUND' or `REAL32 TRUNC', which both give the same (and expected) result in these cases.

NB: the `10.0' divisor corrected above ... because occam only allows division of one type by the same type! And `10' is an INT and occam does also not allow automatic casting ... :-) ... you must say it to get it!!

PS: when casting the other way - from a REAL32 to an INT, we also need to specify what happens to the final bit. This is for a different reason though ... nothing to do with large numbers, but to do with fractional numbers. For example, should 42.7 become 42 or 43? Either may be what is required. What you get is what you say:

    INT i, j, k:
    REAL32 x:
      x := 42.7
      i := INT ROUND x         -- i gets 43
      j := INT TRUNC x         -- j gets 42
      k := INT x               -- will not compile!  (You must say!!)

See also the code on raptor in:


Keywords: cast

Referrers: Question 32 (2012) , Question 53 (2008)

Question 112:


I have a problem with parellel outputs when I make the `fork's report their states. I have one channel coming out of `secure.college' and the compiler says I am making parallel outputs on this channel. Both the forks and philosophers report down this channel. i.e.:

in `secure.college':

      philosopher (..., actionsOut[i], ...)
      fork (..., actionsOut[i], ...)

where `actionsOut' is the channel out of `secure.college'.

Is the only way to do this to have two channels out of `secure.college'. i.e.:

      philosopher (..., actionsPhil[i], ...)
      fork (..., actionsFork[i], ...)

Or is there a better way, as doing it this way will mean the multiplexer has to be much more complicated.


P.S. is there a rough number of microseconds you expect the delay in the philosophers to be or is this en tirely down to our discretion? thanks.

Answer 112:

`actionsOut' is an array of channels, not a single channel. When the replicated PAR expands, each philosopher gets a separate channel (elements of the `actionsOut' array).

For example:

    PROC foo ([]CHAN INT out!)
      PAR i = 0 FOR 5
        bar (out[i]!)

Is equivalent to writing:

    PROC foo ([]CHAN INT out!)
        bar (out[0]!)
        bar (out[1]!)
        bar (out[2]!)
        bar (out[3]!)
        bar (out[4]!)

When the PAR replicator in your first fragment of `secure.college', you end up using the same channel for a parallel `fork' and `philosopher'.

Adding an extra array of channels is one solution, but as you point out, multiplexing this is messier. A better solution is to use channels in the same array, but in a way that avoids `collisions'. This can be done by changing the array subscript expression for either the `philosopher' or the `fork'. E.g.:

      philosopher (..., actionsOut[i], ...)
      fork (..., actionsOut[i+5], ...)

If you expand the PAR replicator, none of the resulting indexes are the same (so no parallel outputs).

In response to your last point, no, not really. The delay must be random, of course (using the random function). As rough guide, somewhere between 2 and 3 seconds, perhaps longer for the `eating' delay. Ultimately, you should find a suitable range, such that the animation runs `smoothly' (not too fast and not too slow).

Keywords: q7

Question 113:


Until recently I had my dining philosophers program running fine with scrolling text output, now I have added the table style animation it runs very slowly and sometimes there is a visible pause as it outputs a word. Are there any obvious things that could be causing this?

I an doing the animations like this:

      clear.states (4 + (4 * n), out)
      cursor.x.y (32, BYTE (4 + (4 * n)), out)
      out.string ("Sitting", 0, out) 
      flush (out)

Thank you.

Answer 113:

Nothing looks wrong with the code you posted. If you're running it over a network (e.g. on raptor logged in from home), that could be the reason. It might also be raptor being slow (with everyone else doing their dining philosophers on it).

Keywords: q7 , animation

Question 114:


I dont quite understand when we should use `flush(out)'. Should this be after every time we make a statement like:

    out.string ("Philosopher ", 0, out)

or after each set of changes such like:

    out.string ("Fork ", 0, out)
    out.int (n + 1, 0, out)
    flush (out)

Answer 114:

After each set of changes. See the answer to Question 91 (2000).

Keywords: q7 , flush

Question 115:

I get an error message saying that the `fork' is incorrectly indented, but I don't know why:

    PAR i = 0 FOR 5
      philosopher (...)
      fork (...)

Answer 115:

You've removed the `PAR' inside the replicated `PAR'. A replicated PAR only replicated one process -- you're trying to give two, hence the indentation error.

The correct way to write this (as in the original `secure.college') is:

    PAR i = 0 FOR 5
        philosopher (...)
        for (...)

Keywords: q7

Question 116:

On the line 'forkStat[0] == 0' I get the following error message. What does it mean ?

    :          IF
 122:            forkStat[0] == 0
    :              SEQ

Error-oc-q7.occ(122)- Operands have different types for operator "=="

Answer 116:

The error is exactly as reported: the operands for `==' are of different types.

Firstly, comparison in occam is just `=' (this is not Java!). At a guess, `forkStat' is an array of channels, and `forkStat[0]' a single channel. You can't compare a channel with anything -- it doesn't have a value. What you need to do (if this is indeed a channel), is input the value first:

    INT x:
      forkStat[0] ? x
        x = 0

It's hard to tell for certain without seeing more of your code (whole `display' process, for example).

When you've got multiple input channels, and want to receive a value from any of them, use an ALT (or replicated ALT if suitable).

Keywords: q7

Question 117:

Whenever I report the number of philosphers sat down, it seems to just report 4 all of the time,

    [snip code]

Answer 117:

This code looks fine. It's most likely an error with the timing/delays in your animation. Without adequate `thinking' delays, the philosophers will always be trying to eat.

Keywords: q7

Question 118:

This is a C assignment question. Whenever I compile the code I get this error:

    raptor$ make load
    gcc -g -Wall -Wmissing-prototypes   -o load load.c
    Undefined                       first referenced
     symbol                             in file
    main                                /usr/local/bin/../lib/gcc-lib/sparc-sun-solaris2.8/3.3.1/crt1.o
    ld: fatal: Symbol referencing errors. No output written to load
    collect2: ld returned 1 exit status
    *** Error code 1
    make: Fatal error: Command failed for target `load'

I don't know why I am getting this as it says symbol missing in `crt1.o' ? Whats happening I can't see any unreferenced symbols in `load.c'.

Answer 118:

There isn't anything missing from `crt1.o' -- that (object) file is the `binding' between your application and the operating-system (more or less). The error is because the linker (`ld') is expecting a function called `main()', which isn't defined in the files the linker was given. Thus the link failed.

I've not looked at the assignment, but at a guess, `load.c' doesn't have a `main()', and it's probably not supposed to.

To just compile `load.c' (and not link it); try:

    raptor$ make load.o

Or to compile the whole lot, just:

    raptor$ make

Question 119:

With reguards to the C assignment, what exactly is a `segmentation fault' and what would cause it ? I keep getting this error everytime I run my C assessment.

Answer 119:

A ``segmentation fault'' is just that -- your program tried to access invalid memory (remember segmentation/paging from CO501). This is more or less an equivalent of Java's `NullPointerException'.

Last year I put together a `quick gdb guide', that should help with solving this sort of problem.

Question 120:

In the question from the 2000 exam paper below what would be the correct answer to what's written below. I know it's because of race hazards it is illegal, but I can't think of a way to rewrite the code.

Consider the following (illegal) outline of an occam system:

    BOOL running:
      running := TRUE
        WHILE running
          ... do operation A
          ... do operation B
          running := FALSE

what was the the system trying to acheive? modify the code so it acheives it legally

Answer 120:

The solution is to use a channel and communication. The 2nd parallel process is easy -- change the assignment to a channel output. Modifying the 1st parallel process is less obvious. Essentially it's a ``check if still `running', and if so, do operation A''. The `check' needs to be modified, but it can't be a simple input. Instead, an `ALT' is required, to select between `communication from the other process' and `nothing'. In code:

    BOOL running:
      running := TRUE

      CHAN BOOL c:
        WHILE running
          PRI ALT
            c ? running
            TRUE & SKIP
              ... do operation A

          ... do operation B
          c ! FALSE

This is polling, that isn't a very pleasant thing to do. Depending on what `operation A' is, it might be possible to move the ALT on `c' inside.

Keywords: race-hazard , exams

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:23 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.