XML

kent logo

CO538 Anonymous Questions and Answers Keyword Index

This page provides a keyword index to questions and answers. Clicking on a keyword will take you to a page containing all questions and answers for that keyword, grouped by year.

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.

Keyword reference for q7

2012

Question 46 (2012):

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 44 (2012):

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

    IF
      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 (2012):

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:
      SEQ
        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
          SEQ
            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 (2012):

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:

    SEQ
      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 40 (2012):

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!
    PAR
      SEQ i = 0 FOR n.philosophers
        secure.college (report!)
      display (report?,screen!)

however if I change this to:

    secure.college(report!)
    display(report?,screen!)

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]

      SEQ
        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 (2012):

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 (2012):

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.

    ALT
      ...  (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:

    ALT
      ...  (Ed: other guards hidden)
      BOOL any:
      left ? any       
	SEQ
          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:

    ALT
      ...  (Ed: other guards hidden)
      BOOL any:
      left ? any       
	SEQ
          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 (2012):

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 (2012):

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)


Question 35 (2012):

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 (2012):

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.

    PROTOCOL REPORT
      CASE
        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!)
      SHARED ! CHAN REPORT r:
      ...  (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 (2012):

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 (2012):

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 (2012):

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 29 (2012):

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.

    SHARED CHAN P.REPORT report:
    CLAIM report?
      PAR
	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 (2012):

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)

2011

Question 52 (2011):

Submission reference: IN2086

Do we need to submit network diagrams this year if we have implemented the basic animation?

Answer 52:

Yes, 'fraid so! The question details (in the Assessment 4 box on the Moodle page) says: "You must also submit relevant network diagrams of your solution ...".

Submission directories will actually remain open until 01:05:00 Tuesday morning. The time now is 23:50:00 Monday evening ...

Keywords: q7


Question 50 (2011):

Submission reference: IN2083

Hi, this is a follow-up to Question 49 (2011). This is the code that I've managed to get to. It compiles but then I get a runtime error in occade on line 1006 "Mobile type error":

    [Snipped]

so that later on I can call:

    [Snipped]

I am trying to condense my code into a more elegant solution by making it replicate in this way. However, I'm having issues with the array of OCCADE.SPRITE chans. To compound this, I am unable to find example code of anything that is trying to do something similar – this makes me think my approach is wrong – but I can not see anything way of achieving this functionality.

Answer 50:

Did the error message say which file in occade that line was from? Or was it from the code you quoted – in which case, which line was line 1006?

You've worked hard getting this far – and I can see you have found workarounds for at least one restriction in occade concerning file names for icon images (which must be mobile byte arrays!). Please submit what you have, with a cover note on your plan for it and what is and is not working. If you have an ASCII art version, submit that as well, again with a cover note saying you have two versions. Thanks.

Keywords: q7 , occade


Question 47 (2011):

Submission reference: IN2080

ok the good news is that i managed to get things moving inside my prgram, ie, things move to diffrent parts of the screen, the bad news however, is that all that are moving are words rperesenting thte various itmes i have some mulitdimensional arrays set up that create stickmen like figures to use instead of the words, but the problem is, that out.string doesnt seem to acept multidimenisonal arrays, is there a way around this?

Answer 47:

You can easily write your own process to output a 2D array of characters (BYTEs) to the screen. For example, here's one (with a testrig program):

    #INCLUDE "course.module"

    VAL [][]BYTE stickman IS [" O ",
                              " | ",
                              "/ \"]:

    PROC out.icon (VAL BYTE x, y, VAL [][]BYTE icon, CHAN BYTE out!)
      SEQ
        INITIAL BYTE yy IS y:
        SEQ i = 0 FOR SIZE icon
          SEQ
            cursor.x.y (x, yy, out!)
            out.string (icon[i], 0, out!)
            yy := yy + 1                    -- move down a line
        out ! FLUSH
    :

    PROC icon (CHAN BYTE keyboard?, screen!, error!)
      SEQ
        erase.screen (screen!)
        out.icon (39, 11, stickman, screen!)
        out.string ("*c*n*n*n*n*n*n", 0, screen!)
    :

Please see opening rant in the answer to Question 45 (2011).

Keywords: q7 , animation , cursor


Question 46 (2011):

Submission reference: IN2079

I get:

    Error-occ21-q7.occ(40)- cannot open file "time.module"

I've looked in lib and sure enough it isn't there...

Answer 46:

This looks like a response to the answer in Question 43 (2011). It looks like the search path set up for you on the Transterpreter doesn't reach all the libraries – which would be our fault.

However, that question was seeking a delay process and I'm assuming that that is what you are still seeking? The function of delay in the "time.module" is, as its documentation says, identical to the pause process given in your starter files for q1, q2, q3 and q4 (and e1). Just copy and use that – it's only these 7 lines of code:

    PROC pause (VAL INT delay)
      TIMER tim:
      INT t:
      SEQ
        tim ? t
        tim ? AFTER t PLUS delay
    :

Keywords: q7 , delay , timers


Question 45 (2011):

Submission reference: IN2078

hye, ive been racking my brains for ages trying to figure out hows to set the minuum number in the randm feature, ive set the maximum, but at the minute i have an if statement that checks whether the number is big enough, and if not, gnerates another one, i can't help thinking that there is a better way of doing this thhats more efficient.

Answer 45:

PLEASE make an attempt to write English when asking these questions. Writing is an important part of the engineering process and correct use of spelling and grammar is necessary in order to be understood. English (and all natural language) is imprecise and full of ambiguities even when well written. Poor English makes things so much worse. When working for real money, poor English will not be accepted!   (End of rant.)

To choose a number randomly between min and max, you are correct to be concerned that using an IF (or some loop) is inelegant and inefficient. Instead: use the random function to choose a number randomly between 0 and (max - min) and, then, add min to it.

Keywords: random , q7

Referrers: Question 47 (2011)


Question 44 (2011):

Submission reference: IN2076

I'm currently trying to get me animation processes running in parallel and I'm not sure how to go about this.

I have the display process receiving inputs on a shared channel from the forks, philosophers, and security that is correctly interpreting the input. But anytime I use one of my animation processes it is done in sequence due to the display process not except another input until the animation process has finished, so everything is animated in sequence.

I've tried all that I can think of to fix this. Any advice?

Answer 44:

See Question 39 (2011). All the forks, philosophers and the security guard processes must have separate report channels (not a shared one) to separate animation processes that can all operate in parallel. The animation processes then compete with each other to send incremental movement messages over the same shared channel to a display process that handles them.

For example, a philosopher animation process might want to move its philosopher icon from one part of the screen to another by some interesting route (e.g. when its philosopher process reports it is hungry). It animates by a sequence of incremental moves (e.g. erase the icon from its current position, which it has to remember, and re-draw at slightly further on along its route). It can hold its philosopher process till this is complete by using an extended input to receive its messages and doing the animation in the extended rendezvous block (see Shared-etc slide 59). The same effect can be achieved without using the extended input syntax (see Shared-etc slide 61, where the ack channel is not needed in this case if you make the philosopher (or fork or security) send each of its messages twice).

Keywords: q7 , shared-channel , animation


Question 43 (2011):

Submission reference: IN2077

I get:

    Error-occ21-q7.occ(133)- delay is not declared

I looked at the occam documentation and it is there! What am I doing wrong?

Answer 43:

Indeed it is: delay. However, if you scroll up from this documentation, you will see that it's in the module time. To use this, you will need the line:

    #INCLUDE "time.module"

somewhere before you use delay in your code (next to the #INCLUDE line for "course.module").

We did not put the delay in the course module. It seemed too simple and you have been using it in many of your provious assignments (where its code was given in the starter files). We did not put it in the starter file for the Dining Philosophers' animation, since many solutions would use TIMERs directly.

POSTSCRIPT: apologies, I was confused by the incosistency in the names we chose! The starter files for q1..q4 have a delay process called pause. This has the same functionality as the delay process called delay in the "time.module".

Keywords: q7 , delay , timers

Referrers: Question 46 (2011)


Question 42 (2011):

Submission reference: IN2074

Thanks for your response to Question 40 (2011) (I am the original question poser).

I understand the concept, however the line of your "set.my.string" example:

      [s[str] FOR s[len]] := [str FOR s[len]]

... produces the error:

      `s' cannot be used (it has been abbreviated)

Why?

Ah! I found the following workaround:

  PROC set.my.string (MY.STRING s, VAL []BYTE str)
    VAL INT str.len IS (SIZE str):
    SEQ
      IF
        str.len > MAX.STRING.LEN
	  s[len] := MAX.STRING.LEN
        TRUE
	  s[len] := str.len
      [s[str] FOR s[len]] := [str FOR str.len]
  :

Can you explain why?

Answer 42:

Sorry about this! When compiling:

      [s[str] FOR s[len]] := [str FOR s[len]]

for some reason, the compiler first transforms it into:

      VAL INT n IS s[len]:
      [s[str] FOR n] := [str FOR n]

Unfortunately, VAL-abbreviating one field of a record variable freezes the whole record, making all its fields un-assignable! (If it is going to do that, it should work a bit harder and apply the freeze rules about VAL-abbreviation just to the field that's been abbreviated. Small part of a project next year?)

Your workaround is not quite correct though. It compiles OK, but always tries to copy over all of the str parameter into the s[str] field in its last line – if the str is too long, this will crash. A correct workaround is to do almost what the compiler is doing, but to use an INITIAL-declaration (which does not freeze the variables making up the initial value) rather than a VAL-abbreviation (which does):

  PROC set.my.string (MY.STRING s, VAL []BYTE str)
    SEQ
      IF
        str.len > MAX.STRING.LEN
	  s[len] := MAX.STRING.LEN
        TRUE
	  s[len] := str.len
      INITIAL INT n IS s[len]:
      [s[str] FOR n] := [str FOR n]
  :

I agree that this is not very elegant!

Keywords: q7


Question 41 (2011):

Submission reference: IN2072

Hey, while writing my dining philosophers' animation, I'm having an issue with my variant protocol. In the display process, I keep getting the error message: "tagname" is not declared. It's declared in the protocol, and I'm using the case keyword when reading in data. I can't seem to figure out what's wrong. thanks.

Answer 41:

You are just getting a compiler error. If you cannot see what's wrong, you have not understood how to declare and use the tags in a variant protocol correctly. We have to see your code to tell you what you are doing wrong – mail me <phw@kent.ac.uk>.

Keywords: q7


Question 40 (2011):

Submission reference: IN2071

Since strings within a list have to be padded (see Question 104 (2003)), I'd like to keep track of the actual length of a string (sans padding).

For example:

    "Cherry Tree": 11
    "Cuban	": 5
    ...
    "Lady Luck	": 9

Now, I believe 3D arrays are one way to achieve this. 2D arrays blow my mind far enough, but 3D takes it to the next level of discombobulation!

This feels like it should work:

    VAL [][][]BYTE a IS [["Cherry Tree", [11]], ["Cuban      ", [5]]]:

... but woefully gives me:

    table elements are of different types

What am I missing? Can it be simplified?

Answer 40:

The issue here is that "[11]" is of type "[1]BYTE", rather than of type "[11]BYTE". The simplest method (in my view anyhow) is to use a RECORD type (which we've now covered in the lectures) along the lines of:

    VAL INT MAX.STRING.LEN IS 128:

    DATA TYPE MY.STRING
      RECORD
        [MAX.STRING.LEN]BYTE str:          --* string data.
        INT len:                           --* actual length of string.
    :

Then you can easily create an array of these things:

    [42]MY.STRING string.table:

You'll probably want some helper PROCs to manage and display these sorts of things, but that's trivial enough:

    PROC set.my.string (MY.STRING s, VAL []BYTE str)
      SEQ
        IF
          (SIZE str) > MAX.STRING.LEN
            s[len] := MAX.STRING.LEN
          TRUE
            s[len] := SIZE str
        [s[str] FOR s[len]] := [str FOR s[len]]
    :

    PROC out.my.string (VAL MY.STRING s, VAL INT padding, CHAN BYTE out!)
      out.string ([s[str] FOR s[len]], padding, out!)
    :

Both of the above bits of code use array slices which haven't been covered in the lectures yet, but their operation is largely straightforward :-) — feel free to read up on them; they're at the end of the Shared-etc. slides.

Keywords: q7 , strings , string-handling

Referrers: Question 42 (2011)


Question 39 (2011):

Submission reference: IN2070

I have followed the plan and have a shared channel, but it seems I can't achieve parallel output of the animation when reports only come in sequence...

My security guard's counter always seems to be out of sync with the actual number of philosophers at the table, but I'm unsure why. Any ideas how to achieve this?

Answer 39:

For the first problem, you may want to consider adding additional processes to help control the animation. Clearly having all the animation handled by "display" which has a single input channel from everything isn't going to work (as you say, it's serialised). What you would need to do is introduce helper processes which do the legwork of the animation and only communicate step-by-step animation actions to the "display" process. That way lots of things can be animating at once without a problem.

As for the issue about the security guard counter, are you flushing the output after writing the integer to the screen? If not, it may be stale. If that's not the problem, try mailing your code to your seminar leader who should be able to spot the problem quickly.

Keywords: q7 , shared-channel , animation

Referrers: Question 44 (2011)


Question 38 (2011):

Submission reference: IN2065

I have connected up my dining philosophers processes and am showing an animation on the screen (hurrah).

However, the reporting of my fork process appears to be running in a strange order. It often reports that it has been picked up on the right before reporting that it has been put down on the right (and vice versa).

I haven't edited the code other than to add in reporting (for both pick up and put down), so I find it odd that this is happening. It seems to me that the display process is simply receiving the reports out of order, rather than anything wrong with the fork process.

Any thoughts as to why this might be the case?

    [snip sensible looking code]

Answer 38:

The code looks fine, i.e. you have something like this (for the benefit of others) in the fork:

    ALT
      left ? any
        SEQ
          ... report fork picked up
          left ? any
          ... report fork put down
      right ? any
        SEQ
          ... report fork picked up
          right ? any
          ... report fork put down

And the display process looks like it's flushing the output appropriately. I don't think the problem is in the way you're reporting, but it may be in what you're reporting. Your reporting here attempts to engineer a philosopher ID from the fork ID, which is bad practice in my view — if the forks and philosophers were reconnected in "secure.college", things would change in less than obvious ways. Double-check that the values emitted by the fork to the display make sense given the philosopher in question. Getting that wrong could easily produce the symptoms you're seeing. It cannot be the case that the reports for a single fork arrive out-of-order since the reporting order is in SEQ.

If you need to know which philosopher is picking-up/putting-down a particular fork, I don't see any harm in changing the "BOOL" signals to "INT"s for the fork-philosopher interaction.

Keywords: q7


Question 37 (2011):

Submission reference: IN2069

This question is related to the dining philosophers project. Currently as it stands the philosophers and forks individually print to the screen when claimed ("thinking, eating, on.table, left.held, right.held") and the security prints the number of philosophers sitting. Theoretically this works however, I am having issues making the philosophers behave randomly as at the moment they do indeed act randomly but the process is rendering really fast for anything to be visibly coherent.

I am using the pause (INT delay) process used in previous exercises to cause the thinking and eating delays, but making this random and at a speed comprehensible is difficult and something I cannot seem to gain.

The following code fragment is from my philosopher process up to claiming the shared report channel to think:

  ...  code omitted
  thinking, s:= random (15, s)
  ...  code omitted
  pause (thinking)
  ...  code omitted

Answer 37:

Your call to random returns a pseudo-random integer between 0 and 14. Your call to pause with that value means a delay of somewhere between 0 and 14 microseconds! Try:

  thinking, s:= random (15*SECONDS, s)

where:

  VAL INT SECONDS IS 1000000:

Keywords: random , q7


Question 33 (2011):

Submission reference: IN2066

Given a string "msg", can I create a second string "underline" that is composed of repeating characters of size "msg"? E.g. in Python:

  a = "hello"
  b = "=" * len(a)
  print(a + "\n" + b)

produces:

  hello
  =====

Answer 33:

Yes:

  VAL []BYTE a IS "hello":
  SEQ
    out.string (a, 0, screen!)
    out.ch ("*n", 0, screen!)
    out.repeat ('=', SIZE a, screen!)    

Keywords: q7


Question 32 (2011):

Submission reference: IN2063

For the Dining Philosophers assessment, should philosophers wait a new random amount of time each time they think or eat, or set one before their loop begins?

Answer 32:

The former – the wait times should be (randomly) different for each wait for each philosopher.

Keywords: q7


Question 31 (2011):

Submission reference: IN2062

Looking at the suggested plan for q7, paragraph (6) mentions: "This may be tricky for fork messages: e.g. it should say the fork number and which phil is holding it".

Does this mean it should print: "Fork 4 picked up by Philosopher 1"?

Or just: "Fork 4 held by right philosopher"?

If it's the former, I can't work out how to do that without editing quite a bit of code.

Answer 31:

It's the former. You will have to know which actual philosopher has picked up that fork later – when you animate the event (rather than just talk about it, which is this initial stage).

If you find you are editing lots of code, there is something wrong with your code. Marks will be lost for code that has repeated sections of logic that are different only in the magic numbers they contain. Make sure you are not doing that! To avoid that, you need some simple algebra involving id-numbers and, when you get on to the animation, some coordinate tables (i.e. VAL [5][2]BYTE arrays). Except, of course, that 5 should be named (e.g. n.phils). The 2 I will allow as it's the number of dimensions in your screen coordinates and is unlikely to change (unless you escalate to a 3-D animation!).

For the question you raised, look at slide 29 of Applying. The philospher that picks up fork id on its left channel is philospher id. The philospher that picks up fork id on its right channel is philospher (id + 1)\n.phils. Simples!

Keywords: q7

Referrers: Question 33 (2012) , Question 33 (2012) , Question 33 (2012)

2010

Question 47 (2010):

Submission reference: IN1944

Hi, I've pretty much finished the animation for q7 but my problem is that one of my philosophers is missing, and s/he's not off the bottom of the screen. I've been to the homework club for 2nd years and they couldn't see any issues with my code. Turns out s/he isn't reporting but code seems to be correct. Any ideas as to why s/he isn't reporting like the others?

Answer 47:

The screen coordinates are [1..80, 1..80], with [1, 1] being the top-left corner. Are you sure your missing philosopher isn't to the left, right or above the screen? Before you did the animation, did you have a display process that just output single lines reporting the messages received and, if so, were all your philosophers showing up then? If not, change your display to do this and make sure all philosophers are reporting. Check (look at your code) that each philosopher (and fork) gets the correct identity number. Check (look at your code) that all variables are initialised before their values are used. Look very carefully at the screen coordinates your philosopher animations are using. Find a way for the dislpay process to print them out, especially from the philosopher that's disappeared.

Hope this helps!

Keywords: q7


Question 43 (2010):

Submission reference: IN1943

A question for q7. For the first 10 or so seconds the philosophers sometimes eat even though the fork next to them is being used by a different philosopher.... after that they behave fine (I think!). I don't understand why this is happening because it was working fine a couple of days ago, :S

My secure.college process looks exactly the same as the one given in the assignment, with no changes made to it (except for the things the assignment wanted me to add) – the same goes for philosopher, fork and security ...

Maybe I'm missing something ... but are there any other places which affect when the philosophers eat?

Answer 43:

Sorry – there's not enough here to diagnose your problem(s). If it worked before, then your current version must be different. When the philosophers eat is determined by when they get hungry and when security lets them in – there is nothing beyond those rules specified in the slides (3-14 and 32 of "applying") and implemented in your starter code (exercises\q7.occ).

Your code is faulty and you have to fix it. Check paragraph 4 of the answer to Question 37 (2010). If your system always goes wrong at the start, check that you always initialise variables (such as coordinates) before using their values. Try changing the eating time from the short random one (required for a good solution) to a long one (e.g. 30 seconds) so that you have more time to look at the screen and work out what's wrong.

Keywords: q7


Question 38 (2010):

Submission reference: IN1933

Hi my program deadlocks ... for some reason when I have VAL INT n.philosophers IS 2: my sequence goes like this:

  philosopher 0 thinking
  philosopher 1 thinking
  philosopher 0 hungry
  philosopher 1 hungry
  philosopher 0 sitting
  philosopher 1 sitting
  philosopher 0 sitting
  total philosophers = 1
  philosopher 0 holding left fork
  philosopher 0 holding right fork
  fork 1 up
  fork 0 up
  philosopher 0 eating
  philosopher 0 put left fork down
  fork 0 down
  philosopher 0 put right fork down

... then deadlock ...

any idea why that might be happening? thanks in advance

Answer 38:

Without seeing the code, it's hard to diagnose. I'd suggest mailing your code to your seminar leader and asking for some pointers as to where things are wrong.

Keywords: q7


Question 37 (2010):

Submission reference: IN1932

Hi there, I'm having a bit of trouble with q7. I've created all my protocols, wired up all the SHARED channels, and created my display process with the CASE statement to spit out the status of the philosophers ...

My program deadlocks when the last philosopher wants to sit down. The problem is that the security process does not manage to get to:

    n.sat.down := n.sat.down - 1

for some strange reason ... and so no philosopher ever stands up.

I know it's probably pretty difficult to diagnose the problem without pasting code ... but any idea why this would happen?

Thanks.

Answer 37:

You're right – it's really not possible to explain your deadlock from the information you have given. :(.

I assume your security process is reporting the number of phils it has let into the dining room whenever this changes? And that is why you know the security guard never counts down? If not, do that.

Check that the eating periods you set for the phils is not very large – that they have the order of seconds (i.e. millions of the microsecs that TIMERs tick to) and not minutes (i.e. hundreds of millions).

Otherwise, nothing springs to mind, I'm afraid. If still stuck, read each of your processes carefully. Ask yourself why should it work – justify this to yourself, as if reading the process for the first time and that someone else has written it. Don't ask why doesn't it work – that encourages you to continue to overlook the mistake you made before (over which you now have a blind spot)! If still stuck, contact your seminar leader ... or me (p.h.welch@kent.ac.uk).

Keywords: q7

Referrers: Question 43 (2010)


Question 36 (2010):

Submission reference: IN1928

Hi. I don't know how to use shared channels to send information to the philosophers on the display. They all are running on parallel, if I use shared channels and have to send some information to just one of the philosophers, I have to include in the philosopher's code a condition, like:

  PROC philosopher (VAL INT me, SHARED CHAN ACTIONS display?, ...)
    INT phil.number, x,y:
    WHILE (TRUE)
      SEQ
        display ? CASE move.philosopher; phil.number;x;y
        IF 
          me = phil.number
            ...

In the sender code there would be something like:

      display ! move.philosopher; phil.number; x;y;

But if I use array channels, I just send the information I want to the concrete phil.number:

  PROC philosopher (VAL INT me, CHAN ACTIONS display?, ...)
    INT phil.number, x,y, message:
    WHILE (TRUE)
      SEQ
        display ? x;y; message
          CASE message
            MOVE
              ...

In the sender code there would be something like:

      display[phil.number] ! x;y; MOVE

With arrays channels I get parallel movements, but not with shared channels. What would be the right way to use shared channels in this case?

Answer 36:

Sorry – I don't understand: "send information to the philosophers on the display"? Your (first piece of) code has the philosopher process inputting messages (ACTIONS) from a display. What are these actions? The "x;y" elements hint that they are coordinates on the screen where you want an icon, representing this philosopher, placed. But ... if so, should this not be a message output by the philospher to the display?

However, if you really want to "send information to the philosophers" (for example, control information to change its delay periods), you cannot use a channel whose input-end is shared by all the philosophers for this. Channels with shared input-ends do not broadcast messages to all receiving processes (which looks like what your code is anticipating). Channels with shared input-ends still carry only point-to-point messages – with receiving ends queueing to be the next receiver (which is enforced by a CLAIM on the shared channel input-end ... that's missing from your code fragment).

As you later note, to "send information to the philosophers", an array of separate channels is needed.

As you also note, the way to get parallel movements (i.e. more than one icon moving at a time) is to output from the icon-representing processes (i.e. phils, forks and security guard) down parallel channels (i.e. elements from an array). The phil/fork/security processes do not need changing from the ones that drove the scrolling lines of text version - other than not using a SHARED report channel, but an array instead. Receiving each report channel can be an animation process that's responsible for remembering where its icon is on the screen and moving it ... by sending messages down a shared channel to a simple display process (that's responsible for simple things like: output this string of characters at these coordinates on the screen).

I do remain fairly confused by your question though. I hope this helps!

Keywords: q7


Question 34 (2010):

Submission reference: IN1931

Hi, I'm still working on the dining-philosophers (q7) assessment and am having real trouble with my animation.

For some reason the terminal takes minutes to display anything, and when it does display something, it takes minutes more before it changes again in response to incoming reports.

I don't know what it is but I'm pretty sure it's not due to my random implementation or my Transterpreter version /computer, as the display process worked when all it had to do was output lines of text.

Any help would be greatly appreciated! Unbelievably confused right now...

Answer 34:

I think this is the same as Question 33 (2010) ...

Keywords: q7


Question 33 (2010):

Submission reference: IN1930

Hi, I'm doing the dining philosophers animation (q7.occ) and the animation loads but it either runs excruciatingly slowly (as in takes minutes to show anything in the terminal) or it just gives me a blank screen.

I know it isn't the Transterpreter or the computer I'm using because the display process ran at the right speed when it was just printing out lines of text. I also doubt if it is to do with the implementation of my random and seed functionality because again this worked with the scrolling text.

Any help would be greatly appreciated!

Answer 33:

Changing to animated output, from lines-of-text output, won't have any noticeable change in the rate at which your program is generating output.

I suspect that you are failing to send a FLUSH to the screen after completing each change on the screen you want to show? When you were sending lines of text, the newline character at the end of each line automatically flushed out the preceding line to the screen. Your animation update bytes probably do not end with a newline – if so, nothing will appear on your screen until the screen output buffer (part of the OS support, not your occam system) becomes full. In that case, you will see nothing for a while ... then, all of a sudden, all your screen animation comes out so fast you don't see most of it ... then nothing for a while ... etc. See Question 91 (2000).

If this is your problem, it's easily fixed – for examples, see Question 25 (2010) and Question 49 (2009). If not, mail me (p.h.welch@kent.ac.uk).

Keywords: q7

Referrers: Question 34 (2010)


Question 30 (2010):

Submission reference: IN1927

Is it possible to declare an array of SHARED channels? "SHARED ! [n]CHAN BOOL lol" gives an error message.

Answer 30:

Nope, unfortunately that will not work; you'll need to declare them individually. This will be fixed in a future version of a compiler.

Keywords: q7 , shared-channel

Referrers: Question 34 (2011)


Question 29 (2010):

Submission reference: IN1925

I'm currently working on the dining philosophers animation but for some reason after making some changes my code refuses to compile - It doesn't produce any error messages but actually seems to break the compiler, giving me the following output:

  Compiling: q7.occ
  skroc: Could not compile q7.occ.
  skroc exited with error code: 1

I've tried the same code on two different machines with two different transterpreter versions (my laptop is running the latest one from the website) and get the same result.

I've tried undoing what I changed to cause such an issue but it doesn't seem to have helped. I appreciate that debugging this may well be impossible without seeing the source code, but I hoped you might be able to suggest what I could possibly have done to cause this.

Thanks!

Answer 29:

Without any more error messages it's a pretty hard problem to diagnose. Although it seems like a daft suggestion, check that the "q7.occ" file it's trying to compile actually exists and is readable, and/or, that the directory it's in is writable. It might also be the case that the "skroc" command cannot find the compiler executable, but if that were the case, I'd expect a more detailed error message (or at least some hint). It may be worth checking the occplug settings to make sure these are sensible (and that the paths referred to exist and contain the expected files). If you still have problems, post again, but please also say what OS you're using and what version of the Transterpreter.

Added later: one of the Transterpreter developers has just mailed:

Given that it mentions skroc in the output it must be a very old version of something. Try to get the student to upgrade?

Are you sure you are using the latest version from the website? What is its version number? You can ask again anonymously ... but it's faster to mail us (phw@kent.ac.uk, frmb@kent.ac.uk).

Keywords: q7 , transterpreter


Question 28 (2010):

Submission reference: IN1926

I've been cracking my head on this prob for the last few days but still can't find a solution.. the program keeps deadlocking for some reason.. I think its some prob with the display process, but can't figure out exactly what.. cheers for any help..

  -- [snip code]

  PROC secure.college ([]CHAN STUFF outs!)
    --{{{  
    [n.philosophers]CHAN BOOL left, right, up, down:
    [11]CHAN STUFF out:
    SEQ
      PAR
        PAR i = 0 FOR n.philosophers
   PAR
     philosopher (i, left[i]!, right[i]!, down[i]!, up[i]!,out[i]!)
     fork (right[i]?, left[(i+1)\n.philosophers]?, out[i+5]!)
        security (down?, up?, out[10]!)
    --}}}
  :

Answer 28:

The problem lies in your "secure.college" process. The process header specifies an array out output channels ("outs"), which are ultimately connected to the "display" process. However, within that PROC you declare another array of channels ("out"), and then plug that into the various sub-processes! The effect is that when any of these tries to output to its reporting channel, it'll immediately deadlock, since there is no process connected to the input ends of the "out" channel. In effect, remove the "out" declaration, and wire in the "outs" channels instead.

Keywords: q7


Question 27 (2010):

Submission reference: IN1923

Hi there, I've a little timing problem on the q7

  phil.0:MAY I SEAT DOWN? 
  phil.0:I'M SITTING
  security:SEAT NUMBER 0. PHILOSOPHERS AT THE TABLE 2

Is that normal? Do I have to put some delays on the philosophers process?

Answer 27:

It looks like your philosopher process reports the first line (of your above messages), then communicates with security, then reports the second line. And your security process reports the third line when it gets the communication (I just assumed) from a philosopher.

If so, after the communication between the philosopher and security, both processes continue in parallel and try to report their states (the second and third lines). Of course, those reports (and, hence, lines) may appear in either order.

If we need to control the order (e.g. so that the security guard makes its report first), we don't do it by putting in delays! The scheduling would then become dependent on the length of the delays. If this were a real-time control system, many changes in the coding and the platform processors will happen over its lifetime maintenance ... and timing figures that were once correct can become incorrect.

Instead, control the order by putting the control in the logic of the code. For example, if the security process were to accept the philosopher request (to sit down) with an extended input and make its report in the extended rendezvous, that report would be complete before the philosopher became aware that its request had been taken – so the philosopher's report would be bound to follow that from security. No delays are needed to manage the scheduling, :).

Keywords: q7

Referrers: Question 28 (2012)


Question 25 (2010):

Submission reference: IN1920

I'm trying to achieve parallel animation but now that I have various animation processes the location of characters on the screen has gone crazy. For example philosophers and forks turn up where the number seated should be displayed. I'm guessing this is because my third parameter for cursor.x.y is the connection between the respective animation process and the display process. Does it need to directly link to the screen to work properly? My code works fine if I do all the animation stuff within the display process and I'm CLAIMing the channel before output so I can't see what else could be the problem.

Answer 25:

The third argument to cursor.x.y could be any channel carrying BYTEs. Normally, this would be the screen channel but it doesn't have to be (but, in that case, the BYTEs would need to be forwarded eventually to the screen channel to be seen). Care would have to be taken to keep sequences together that need to be kept together (e.g. screen control sequences and the text they are placing!).

It sounds like you are not doing this with enough control? If you have parallel animation processes writing to the same SHARED channel, the channel must be claimed for the whole of each individual animation movement. For example, don't do this:

  SEQ
    CLAIM to.screen!
      cursor.x.y (x, y, screen!)
    CLAIM to.screen!
      out.string ("  ", 0, screen!)
    CLAIM to.screen!
      cursor.x.y (x+1, y, screen!)
    CLAIM to.screen!
      out.string (":)", 0, screen!)!)
    CLAIM to.screen!
      to.screen ! FLUSH

because other process can interleave their CLAIMs in between the above ones, with resulting chaos like you described. Instead, do this:

  CLAIM to.screen!
    SEQ
      cursor.x.y (x, y, screen!)
      out.string ("  ", 0, screen!)
      cursor.x.y (x+1, y, screen!)
      out.string (":)", 0, screen!)
      to.screen ! FLUSH

Now, the cursor control sequences and associated texts will stay together. This process has exclusive use of the claimed channel throughout the CLAIM.

Keywords: q7

Referrers: Question 33 (2010)


Question 24 (2010):

Submission reference: IN1919

Hey, Is it possible to use an input channel as a guard if its type is a CASE protocol? It doesn't seem to allow me to declare variables of type CHOICES which is understandable but I can't work out how else I can PRI ALT over one channel containing the reports and another input channel that takes in commands. I'm basically trying to implement pause functionality but it seems I can only get this to work if I use an extended rendevous within the display process (I want all processes that output onto the shared CHOICES channel to halt execution until the indented code is executed). Maybe there's a better approach?

Incidientally if I'm unable to get this implemented, would it have much affect on my mark? I plan on doing parallel philosopher animations where you can change the speed at which the philosophers move but I need some help from my seminar leader before I start implementing this.

Answer 24:

Yes. Any channel, carrying any kind of protocol, can be used as an input guard in an ALT (or PRI ALT).

I'm guessing your CHOICES is a (CASE) PROTOCOL you have declared? If so, you can't declare variables with 'type' CHOICES:

  CHOICES x:     -- will not compile

A message protocol is carried by channels – it's not a type with which variables can be declared. To input from a CASE protocol, we don't write:

  in ? x

Instead, there is a special syntax – see slide 70 of the "protocol" slides. Then, you will be able to ALT between channels carrying reports and another carrying commands.

There won't be too many marks for implementing a pause – it's very simple, if you do it right ... ;)

Keywords: q7


Question 22 (2010):

Submission reference: IN1917

Hey, I have a couple of questions regarding Q7. is it possible to concatenate a variable within a string? So instead of using:

  SEQ
    out.string ("phil no: ", 0, out!)
    out.int (i, 0, out!)

you could have something like:

  out.string ("phil no: " + i, 0, out!)

Also, can deadlock be caused by not flushing the screen in the correct place? Or by something similar as I currently have the following inside my display PROC:

  ...  code omitted

and this currently gives the output:

    philosopher number: 0 is 0
    philosopher number: 1 is 0
    philosopher number: 2 is 0
    philosopher number: 3 is 0
    philosopher number: 4 is 0
    philosopher number: 0 is 1
    philosopher number: 0 is 2
    philosopher number: 0 is 3

before deadlocking.

Answer 22:

To allow:

  out.string ("phil no: " + i, 0, out!)

we need an operator, "+", between a string of arbitrary length (left operand) and an INT (right operand) giving a string result. Arbitrary length strings can be defined as MOBILE arrays (see slides 2-19 on "mobiles", especially slide 14). New operators, beyond those built into the language, can be user-defined. They are side-effect free (just like FUNCTIONs) and are defined using (almost exactly) the same syntax as FUNCTIONs. Sorry, there are currently no notes/slides on this, but they are described, with lots of examples, on this web page and in this paper.

So, sorry! Without arbitrary length strings and user-defined operators, we can't do what you want – we have to output strings and integers separately using separate procedures (e.g. out.string and out.int).

Re. your second question: no, sending a FLUSH to the screen should have no impact on dealock issues. FLUSH is just another BYTE, so sending it has no special synchronisation meaning in occam semantics. Your code outputs several lines before sending just one FLUSH. That is fine! Your output looks wrong (?) but your FLUSH is not the cause of your deadlock.

Keywords: q7


Question 19 (2010):

Submission reference: IN1914

I am wanting to use the various raster graphics libraries to do my dining philosophers with, but the problem I am having is that the SDL raster interface (http://occam-pi.org/occamdoc/sdlraster.html) uses channels of type "RASTER" to output the graphics on the screen but all the other raster libraries use channels of "INT[][]".

I have looked through the documentation and cannot find a way to convert the INT[][] to RASTER, unless I first output it as an image file (which is hardly efficient when doing animations).

Is there a process that will convert the INT[][] to RASTER or some other way of displaying the images that uses INT[][]?

Answer 19:

Have you tried compiling code that uses both of these? The RASTER type is defined to be a "MOBILE [][]INT". Although we haven't taught you about MOBILE types yet (which use a movement semantics rather than copying semantics), you should be able to pass RASTERs to procedures that expect [][]INT parameters (although not vice-versa). Within your own code, it'd be more efficient to use things like "CHAN RASTER" rather than "CHAN [][]INT", as the latter will take an appreciable amount of time to copy large graphics windows. We'd recommend just trying to compile your code as-is, and if you run into any specific type errors, ask here again :-).

Keywords: graphics , q7

2009

Question 50 (2009):

Submission reference: IN1851

Hi there, I'm currently doing my animation for dining philosophers, and I'm trying to make the animations happen in parallel, but I can't figure out how to do this.

I have a case statement that reads in the reports on the report channel, then depending on what comes in, does the animation. But until the animation finishes, I can't finish the CASE to get the next command in to animate that.

Is there someway to get the CASE to loop round and start dealing with the next report while the body of one of the case commands is still running? Or if not, any other suggestions about how to deal with this problem? Thanks.

Answer 50:

As you say, you can't do this with a single display process. See the last two paragraphs of the answer to Question 49 (2009).

Keywords: q7 , animation


Question 49 (2009):

Submission reference: IN1849

In Question 48 (2009), you answered:

"You have to erase the string-icon (by writing spaces where it used to be) just before you write it in the next position (and FLUSH)".

I'm sorry but I don't understand what you mean. Could you explain further? Sorry.

Answer 49:

For instance:

    VAL []BYTE icon IS ":0":                        -- 1-D (horizontal) icon

    SEQ
      cursor.x.y (string[X], string[Y], screen!)
      SEQ i = 0 FOR 5
        SEQ
          out.string (icon, 0, screen!)
          screen ! FLUSH
	  pause (50000)                             -- 1/20 second
	  cursor.left (SIZE icon, screen!)          -- move cursor back
	  out.ch (' ', SIZE icon, screen!)          -- erase icon
          cursor.right (1, screen!)                 -- next icon position
      screen ! FLUSH

Note: in the above, the icon moves right by 1 position in each cycle. In your code in Question 48 (2009), your icon moved right by 3 places each cycle (leaving a trail).

If you do this in the standard display process, only one icon will be animated at a time. For parallel icon animations, you will need parallel animation processes writing to a fairly dumb display process over a SHARED channel.

With the assessment due today, you probably don't have time to bother with parallel animation! For future work, take a look at the shared_screen module.

Keywords: q7 , animation

Referrers: Question 33 (2010) , Question 50 (2009)


Question 48 (2009):

Submission reference: IN1848

I'm trying to move a string using but it keeps leaving a trail of the character behind:

    SEQ
      cursor.x.y (string[X], string[Y], screen!)
      SEQ i = 0 FOR 5
        SEQ
          out.string (":0", 0, screen!)
          screen ! FLUSH
          cursor.right (3, screen!)

Answer 48:

You have to erase the string-icon (by writing spaces where it used to be) just before you write it in the next position (and FLUSH).

You also need to leave a decent time interval between each move – say 1/20th of a second ... but experiment!

Keywords: q7

Referrers: Question 49 (2009) , Question 49 (2009)


Question 44 (2009):

Submission reference: IN1845

I've managed to do the dining philosophers but I'm worried about whenever I think about ? and ! it takes far longer than it should. It like takes around 20 secs per item. My thinking is if you have independent processes, you think about them from the view point of the process. However, then when you have processes within processes, I then get confused. Internal channels don't need direction specifiers because it is a pipe. But matching the process header with the call etc. Particularly, with external channels, what you would consider the writing end, is often the reading end etc...

Is this normal or do you know the answer instantly?

Answer 44:

As you said, processes should be considered from their own point of view – process orientation!

Let's assume here that by process we mean something defined by a PROC declaration.

External (i.e. parameter) channels to which the process outputs (!) messages often have names containing "out", "write", "to" or "send". External channels from which the process inputs (?) messages often have names containing "in", "read", "from" or "receive".

[Aside: it's safer to use the terms write and read, rather than out and in. From the point of view of either a process or a channel, the writing end of the channel means the same thing. However, the outputting end of a channel from the point of view of the process doing the output is the inputting end of a channel from the point of view of the channel! And vice-versa. Note that send and receive are safe names ... as are to and from. When in doubt, use names from the point of view of the process. Better is to use terms that are unambiguous (like write/read or send/receive).]

The writing (!) end of a channel remains the writing end whether you think about it from the point of view of the the process body (i.e. as a parameter) or the network builder (i.e. as an argument to plug into a process). So does the (?) end.

When building a network (e.g. for the implementation of a PROC body), full channels will be declared (i.e. not qualified by ! or ?). When plugging channels into processes, plug !-ends into !-parameters (i.e. writing or sending channel parameters) and ?-ends into ?-parameters (i.e. reading or receiving channel parameters).

Simple! :)

Keywords: q7


Question 43 (2009):

Submission reference: IN1843

How's the effect of moving the characters (philosophers, forks, ...) achieved with the co-ordinate arrays?

Answer 43:

See Question 68 (2000) and Question 104 (2004) (and other questions and answers under the cursor and animation keywords).

Keywords: q7 , cursor


Question 42 (2009):

Submission reference: IN1842

I'm currently working on my occade animations in Q7, having done all of the basic stuff (I think!). The number of warnings I'm getting has gone up considerably, whilst the program still works fine. Some of them are probably quite trivial and easily solved, so I'm pretty sure I could reduce the number.

If I ignore my warnings and complete the animation, and run out of time to go back and address the warnings, will it affect my mark?

Answer 42:

Try to clear them up ... but we know that the compiler is over-cautious and issues many warnings on code that a deeper analysis would show is safe. But that's what warnings are for: to draw your attention to things that it (the compiler) is unsure about, leaving you to check their safety yourself. A lot of this happens, I'm afraid, when compiling some of our library codes! You can certainly ignore those warnings.

So, no. Warnings issued by the compiler on your code will not lose you marks – so long as the things it is warning about are really OK.

Keywords: q7


Question 40 (2009):

Submission reference: IN1841

Hi there, I'm having a strange problem trying to pass my shared channel to where it needs to go.

    ...  code omitted

provides me with this error:

    Error-occ21-q7.occ(182)- must CLAIM `reportChan!' before using channels
    skroc: Could not compile q7.occ.
    skroc exited with error code: 1

and I don't understand why. It's more than happy to let me pass reportChan to philosopher and fork. I can delete the security line and it compiles fine. I can't imagine why it insists on me claiming the channel to pass it to security. At no point in my code am I writing to channel yet anyway! Am pulling my hair out. Help much appreciated! Thanks

Answer 40:

There was not enough information in the code fragment you included to answer your question. Also, we cannot reproduce such code fragments (containing too much solution code) in these questions.

However, check that your security guard process declares its reportChan channel as SHARED. Failing that, mail me or your seminar leader your code and repeat your question.

Keywords: q7 , shared-channel


Question 38 (2009):

Submission reference: IN1838

I want to draw a pentagon made out of '+' as a table for the Philosophers but I don't know how to go about it. How would I deal with the angles accurately?

Answer 38:

You can't - not with an animation made using ASCII characters on a rectangular grid (your terminal window)!

You can only approximate – e.g.

    VAL [][]BYTE pentagon IS ["  ++++++  ",
                              " +      + ",
                              "+        +",
                              " +      + ",
                              "   +  +   "]:

and print that wherever you want it in the scene.

Keywords: q7


Question 36 (2009):

Submission reference: IN1836

I've been told that I have to use cursor.x.y to create the interface, however, I don't understand how that would work. Could you explain it to me please? Thanks.

Answer 36:

See slide 14 from these slides and this documentation. You should also look at test-utils.occ from your examples folder and check out the cursor keywords entries in the anonymous Q&As.

Keywords: q7 , cursor


Question 35 (2009):

Submission reference: IN1834

I am trying to get random text to scroll in occade. My current method involves creating a sprite and then loading text using a font/image package.

However I want to change this text often. So far I have this methodology:

Before I try and bodge a way of doing this, is there an easy/ier way of doing this?

Also does occam provide a way of pushing a value to an array? Thanks.

Answer 35:

Adam Sampson (ats@kent.ac.uk) writes ...

Sounds like you have it pretty much figured out already. :)

You don't need to create a new sprite each time -- you can just create one sprite, make it visible, then send it the "load.text" message each time you want to change the message it's displaying. The score displays in Parrot Attack work this way, for example.

To insert a character at the start of an array, the easiest way is just to shift everything else up by one -- copy the second-last character over the last, then the third-last over the second-last, and so on. You can do this using a replicated SEQ with the STEP keyword to make it count backwards.

Here's what that looks like as an Occade program:

    #INCLUDE "occade.module"


    PROC demo.text.maker (CHAN BYTE c!)
      WHILE TRUE
        SEQ ch = 'a' FOR 26
          SEQ
            c ! BYTE ch             -- the replicator control variable is an INT.
            occade.delay (100000)   -- set whatever speed your display can take.
    :


    PROC display.text (SHARED OCCADE! occade, CHAN BYTE c?)

      VAL INT LEN IS 20:
      INITIAL [LEN]BYTE buf IS [i = 0 FOR LEN | ' ']:
      -- we've not told you about the "array comprehension" syntax above ...
      -- it just constructs an array of size LEN, filled with spaces.

      OCCADE.SPRITE! sprite:

      SEQ

        occade.start.sprite (occade, sprite, -1)
        sprite[req] ! load.text; buf; "images/font10x20.png"
        sprite[req] ! move; 320; 240; TRUE
        sprite[req] ! visible; TRUE

        WHILE TRUE
          BYTE ch:
          SEQ
            -- wait for new byte char to arrive on channel
            c ? ch
            -- add this new byte char to the start of my array
            SEQ i = LEN - 1 FOR LEN - 1 STEP -1
              buf[i] := buf[i - 1]
            buf[0] := ch
            -- update the sprite
            sprite[req] ! load.text; buf; "images/font10x20.png"
    :


    PROC main (CHAN BYTE kbd?, scr!, err!)

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

      SEQ

        params[width] := 640
        params[height] := 480
        occade.start (occade, params, "Scrolly text demo")

        CHAN BYTE c:
        PAR
          demo.text.maker (c!)
          display.text (occade, c?)

    :

Keywords: q7 , occade


Question 34 (2009):

Submission reference: IN1829

When attempting to assign a background in occade using:

    occade.load.playfield (occade, "images/background.png", 0, 0)

I get the following error:

    STOP error
    The error occured on or around line 41 in rasterio.occ

The occade window loads correctly prior to that statement being made.

Answer 34:

Adam Sampson (ats@kent.ac.uk) writes ...

To load PNG images, you need a KRoC that's been built with support for the libpng library. (You can't do this for the Transterpreter because it relies on CIF – although I think Carl had a fix for that in the LLVM branch?  If you don't know about CIF and LLVM and are curious, come and ask us, :)

But if you have occade working, a quick workaround would be to use images in BMP format instead; SDL has built-in support for loading BMP files, so occade can always do that.

Keywords: q7 , occade


Question 33 (2009):

Submission reference: IN1835

Hi there the kroc compiler is making weird complaints.

    ?????@?????-???????:~/raptor/private/co538/assessment4$ occbuild --program q7.occ
    Fatal-occ21-q7.occ(75)- unknown tag N_SPROTDEF in pi_valcheck

    *********************************************************************
    * The compiler has detected an internal inconsistency.		    *
    * Please email kroc-bugs@kent.ac.uk with a copy of the code which   *
    * broke the compiler, as this is probably a compiler bug.	    *
    * Please include the KRoC version and any other relevant details.   *
    *********************************************************************

    kroc: /usr/local/kroc/bin/occ21 failed to compile q7.occ to q7.tce

What is this complaining about? any ideas how I fix it?

    ...  code removed

Answer 33:

Protocol extension is only allowed between variant (i.e. CASE) protocols. Your line 75 tries to extend report protocols for phils, forks and security – but only the fork reports has variants. Your definitions are easily corrected – change:

    PROTOCOL SECURITY.REPORT IS INT:

to the single-variant:

    PROTOCOL SECURITY.REPORT
      CASE
        security; INT
    :

and similarly for your phils report protocol.

But our compiler shouldn't have blown up! It should give a decent error report. I'll pass on a bug report - thanks.

Keywords: q7 , protocol-inheritance


Question 30 (2009):

Submission reference: IN1830

Could I clarify that the only use of a shared channel is that you get a free FIFO mechanism for handling requests? As opposed to implementing a FAIR ALT – this doesn't actually exist does it?. Numerous channels per se aren't bad - it's not we are going to run out of channels? Or is it to declutter things?

Thanks,

Answer 30:

A shared channel writing-end means that the writing processes are FIFO queued to do their writing on that channel – which is fair. If the other (reading-)end is not shared, than the single reader there will automatically provide a fair service to all writers.

The above is simpler than having a number of classic channels (with non-shared ends) from all the writers to a single reader, with the reader having to be programmed with fair-alting logic to provide a fair service. There are times when we have to do this though – e.g. when the protocols on the channels have to be different (although this can usually be overcome with variant protocols and variant protocol inheritance) or when fair service for some channels has to be balanced with prioritised service for others.

You are right that occam-pi does not support the notion of FAIR ALT as a language mechanism. That would not actually make sense, since the notion of fairness only is relevant when many executions of the ALT take place. The question of fairness for a single ALT does not arise. If fairness were introduced at the language level, it would have to be in terms of a loop that services a set of channels – e.g.

    FAIR SERVER i = 0 FOR SIZE in?
      in[i] ? x
        ...  deal with x

which would mean something like:

    VAL INT n IS SIZE in?:
    INITIAL INT favourite IS 0:
    WHILE TRUE
      PRI ALT i = favourite FOR n
        VAL INT i.mod.n IS i\n:
        in[i.mod.n] ? x
          SEQ
            ...  deal with x
            favourite := i.mod.n + 1   -- channel just serviced become least favoured

where we have used classical fair alting logic (see Question 62 (2007)).

FIFO servicing of channel inputs is not the only benefit of shared channels. The reading ends of channel may also be shared, which provides for fair distribution of messages from a single writer. And both ends of a channel may be shared, which provides a fair brokerage service for putting reader and writer processes in touch.

As you say, numerous channels are not necessarily to be avoided. After all, each one only requires one word of storage (to hold a reference to a waiting partner – or nil if no process is waiting). But if you can replace an array of channels with one shared channel, that does tend to simplify the picture and associated logic.

Keywords: q7 , fair-alt , shared-channel


Question 29 (2009):

Submission reference: IN1828

I've added the following output channel to the philosopher: CHAN PHIL.STATE report! PHIL.STATE has been defined as a CASE protocol. secure.college outputs an array of this particular protocol type to the display method. This is defined in the secure.college header like so:

    CHAN [n.philosophers]PHIL.STATE phil.out!

However, when attempting to assign each philosopher in the replicated PAR to a particular point in this array I get an error: "phil.out subscripted too many times". I am assigning it as follows:

    philosopher (i, left[i]!, right[i]!, down[i]!, up[i]!, phil.out[i]!)

What does this error mean? Am I doing something completely wrong?

Answer 29:

Your declaration of the channel array phil.out is wrong. You have declared a single channel that carries an array of PHIL.STATE messages (in each message):

    CHAN [n.philosophers]PHIL.STATE phil.out!

You need an array of channels, each one carrying a single PHIL.STATE in each message:

    [n.philosophers]CHAN PHIL.STATE phil.out!

Now, phil.out[i] references element i from the channel array. Before, phil.out was not an array, so adding the array subscript was an array subscript too many - as the error message says!

But there's something wrong with our compiler! occam-pi currently does not support the concept of an array of PHIL.STATE messages. On encountering your [n.philosophers]PHIL.STATE, the compiler should have thrown an error message of the form:

    Error-oc-charray.occ(line-number)- Name PHIL.STATE is not a TYPE

Investigating ...

Keywords: q7 , arrays , channels

2008

Question 38 (2008):

Submission reference: IN1650

Hi, Not that I really mind this time around as I had already submitted my solution for q7, but I believe the submission directory was closed 54 minutes early at 23:05pm (according to the time I recieved the email), rather than 23:59pm as stated on the module webpage.

With all the work I have to do in these last few weeks of term (hense why I am sadly working late on a Tuesday evening!), I may need all the time I can get for the next assessment, so please could you state the correct time for submission of the last assessment on the module webpage.

Thanks!

Answer 38:

Sorry! As explained elsewhere, this was our mistake (which we will try and not repeat next time).

Anyone who mailed us their assessment (or an updated version of their already submitted assessment) had that mailing accepted as their actual submission. If there is anyone else who was not aware of this and feels they missed out, please contact us. Thanks.

Keywords: q7


Question 37 (2008):

Submission reference: IN1648

Hello, I am having a timing issue with my fork animation. At the moment it appears as though a philosopher is dining with one fork. However, the other fork is displayed but a bit later on (quite often after the philosopher has finished eating). Is there a way I can have my case statements for the left and right pick ups be carried out in parallel?

Thanks.

Answer 37:

Sorry – this question came in just three and a bit hours before the assessment was due, which was too late to be answered, I'm afraid!

The display process should only deal with one report at a time (since the screen channel, used to drive the display, is a serial device). So, there is no point in it being able to deal with reports about left and right pick ups in parallel.

Did you remember to FLUSH the screen output made by your display process at the end of its response to each received report? If you did not, the screen outputs would not reach the screen until a buffer (somewhere in the system, outside your occam program) fills up ... and screen updates would be very very bursty.

Keywords: q7


Question 34 (2008):

Submission reference: IN1643

Hi there, I am having a little bit of a problem in connecting up my shared report channel. I get the error message (type mismatch for parameter 1 in secure.college), but I can't see where I am going wrong. I have declared the channel passed to the secure.college as SHARED and I have a SHARED CHAN within my q7 process that I pass to secure.college. I'd be grateful if you could possibly point me in the right direction. Within q7:

  SHARED CHAN P.DISPLAY reporter:
  secure.college (reporter!)

header of secure.college :

  PROC secure.college (SHARED CHAN P.DISPLAY reporter!)

Thanks,

Answer 34:

The code you have written in the question looks fine, though in this particular case, the "reporter" channel should only be shared at its output end, i.e. be declared:

  SHARED! CHAN P.DISPLAY reporter:

This is on the (usual) understanding that the "display" process reading from the shared channel is the only process doing so. As you're seeing a "type mismatch" error at the point of the procedure call, double-check that the code is as you have it above. Specifically, check that there is not anything else also called "reporter" declared between that shared "reporter" channel and the error-generating call to "secure.college". For example, the following code will generate a similar error:

  PROC foo (CHAN BYTE out!)
    INT x:
    SEQ
      x := 42
      ...  some other code
      INT out:
      SEQ
        out := 19
        out.string ("Hello, world!*n", 0, out!)
  :

In a similar way, also check that the "secure.college" you mention is the only one declared at the top-level. For instance, if you had:

  PROC foo (SHARED CHAN BYTE out!)
    ...  stuff
  :

  PROC bar ()
    ...  stuff
  :

  PROC foo (CHAN BYTE out!)
    ...  stuff
  :

  PROC baz ()
    SHARED! CHAN BYTE c:
    PAR
      ...  some process reading from 'c'
      foo (c!)
  :

This will also generate a type-mismatch error, since there is another "foo" procedure declared between the one you intend to use (with a shared channel parameter) and the point where it is called (in "baz").

If you can't spot the error yourself, try mailing your seminar leader with the code and asking for help (we're a bit more used to tracking down errors in occam-pi programs quickly!).

Keywords: shared-channel , q7


Question 33 (2008):

Submission reference: IN1640

Hi, I'm trying to refine my reporting for the dining philosophers assessment. At the moment I have the philosophers report via the secure.college process which communicates with a display process. Is it okay to leave it like this, or do we need to have the philosophers reporting directly to a display process?

Cheers.

Answer 33:

Each philosopher, each fork and the security guard should make reports on an external (i.e. parameter) report channel. Those processes do not care where that report channel goes – that's not their responsibility.

The above processes are run in parallel by secure.college. This process needs its own external (i.e. parameter) report channel (if SHARED) or array of channels (if not). All secure.college needs to do is connect its external report channel (or channels) to the instances of philosopher, fork and security it is running. There is nothing else for secure.college to do! In particular, it should not attempt to receive reports from its sub-processes and relay them onwards – that would be a waste of time. See slide 60 from the applying slides for a diagram (where secure.college has been re-christened reporting.college).

So, yes, each philosopher (and fork and security) will be reporting directly to a display process. But all they know is that they make reports. The secure.college, which runs them, connects their report channels to its given report channel(s) and knows/cares not where they go. It's the responsibility of whatever is running secure.college – in this case, your q7 process – to connect the report channel(s) from secure.college to a display process.

Keywords: q7


Question 32 (2008):

Submission reference: IN1639

Hi there, I have a question about the current assessment. I am a little confused as to what the security guard should be doing. Am I right in thinking that it only needs to report the number of philosophers currently inside the college (i.e. sitting and eating)? And that this value should be gained by each philosopher reporting its state to the process via a protocol?

Thanks.

Answer 32:

Security already keeps a count of how many philosophers have been admitted (i.e. the number sitting, but not necessarily eating since their forks may not be available). Initially, and whenever this count changes, security should report the new value.

Note that security should do this (via a suitably protocolled report channel). There is no need to pass this information to any philosopher and get them to make the report. For a basic solution, all reports (from philosophers, forks and security) should be received by a display process and animated.

Keywords: q7


Question 31 (2008):

Submission reference: IN1635

I'm a little confused as to whether we are supposed to control timing issues only in the philosopher process or also through the display process?

Answer 31:

For the basic solution, only the philosopher needs to manage time delays (for modelling thinking and eating periods). For more sophisticated animation (e.g. showing actual movement), extra animation processes will use delays to space out updates after moving to new positions. The display process itself should be fairly dumb, just being responsible for placing text in response to client requests (from the philosopher and any animation processes).

Keywords: q7


Question 30 (2008):

Submission reference: IN1633

My dining phils program is working but I'm worried about my code! It's got great chunks of code repeated with the only difference being magic numbers for all the different coordinates needed to make reports in the right places for the different phils and forks.

Should I be concerned? Thanks.

Answer 30:

You should be concerned!

Check out the keyword index page for q7 and use your browser to search for "magic". Especially, discover Question 68 (2000), Question 104 (2004) and Question 103 (2006) ... :)

Keywords: q7


Question 29 (2008):

Submission reference: IN1628

I've read through the previous answers, but I'm still having trouble setting the seed. I understand that the seed is declared in the q7 process in order to receive a value from the keyboard, so are we expected to find a way of passing the seed to the philosophers from within the q7 process? Also, should our animation (modelled on a7-basic) still work without the seed set?

Answer 29:

I don't understand what you mean by: "the seed is declared in the q7 process in order to receive a value from the keyboard"?

A seed should be declared and initialised in the q7 process in order to pass unique seeds to the philosophers, which they use in generating random numbers for setting randomised thinking and eating periods. Code for declaring and initialising such a seed is given in your starter file.

Passing the seed to the philosophers is easy: pass it (as a VAL INT parameter) to secure.college and secure.college passes it on (as a VAL INT parameter)to each philosopher, when it instances each philosopher (in a replicated PAR).

The secure.collegeshould also pass a unique id number to each philosopher. Adding that id to its given seed results in a unique seed for each philosopher.

Everyone should trawl through the anon Q&As for information. For instance, check out the keyword index pages for random and q7 and use your browser to search for "seed". You may find Question 55 (2006) particularly helpful.

Finally, if you don't set a seed and pass it on properly, your animation will not be randomised. The random number function requires a seed argument and returns an updated seed value as the second part of its answer (the first part being, of course, the random number it choose for you). Make sure you know how to use this function properly.

Keywords: q7 , random


Question 27 (2008):

Submission reference: IN1631

I'm getting a runtime error: CSUB0 at or around this code:

  INITIAL INT l.offset IS (id * 4) - 1:
  INITIAL BYTE r.off IS BYTE r.offset:

where id is an INT I'm then attempting to add r.off to another BYTE value in cursor.x.y. I'm essentially trying to cast an INT to a BYTE value. The INT value should be in the range 0-255, so I'm not sure what the problem is I'm encountering.

Answer 27:

First, apologies for the dreadful name (CSUB0) in the error message! CSUB0 is one of the byte codes generated by the occam compiler. Its used for checking ranges: array indices, CASE input tags, type range violations (e.g. for BYTEs). The latter is probably what's happening here.

So long as 0 < id ≤ 64, then 0 ≤ l.offset &le 255 and casting it to a BYTE will be OK.

However, if id were ever to be zero, then l.offset would be -1 and casting it to a BYTE would be illegal and raise an error.

You do, though, cast something called r.offset in the code you quote and say nothing about its value. Might this be your error?

Assuming the casting of r.offset to (your BYTE variable) r.off worked, adding some BYTE (e.g. r.off) to some other BYTE value may overflow (i.e. result in a number greater than 255).

Keywords: q7 , csub0


Question 25 (2008):

Submission reference: IN1619

I'm trying to model my q7 on a7.basic, but I'm having difficulty displaying any sort of sensible output. The phils, forks and security each output their state via a shared channel to the display, which outputs to the screen based on which channel the input was received on, using the id of the forks and phils to output to the correct column/row on the screen. However, my display only ever shows (almost) all the phils and forks in all the states at the same time. However, sometimes there is no display to the screen at all. I'm not sure whether it's because I'm not setting my seed correctly, of if its a more general problem with the wiring.

[snip code]

I'm also curious to know why in a7.basic the philosophers often skip the hungry and sitting states, going straight from thinking to eating. Surely the progression through the states happens sequentially?

Answer 25:

The code you had there looks fine, so I don't think that's the problem. Check, however, that your display process is flushing the output correctly. That is, terminal output is line-buffered by default, so you normally wouldn't see program output until a newline occurs. You can force the output by writing the FLUSH value to the screen channel, or by including a newline at the end of every chunk of output sent to the screen. That would be my first thought, anyway. Incorrectly set seed values are more likely to result in a non-random animation, rather than a broken animation.

PHW adds: if your display shows all phils and forks in all states (almost) all the time, are you erasing text indicating a previous state when writing the text for the new state? To erase previous text, just overwrite with space characters – of course, you have to work out where the text indicating the previous state is on the screen (but that's no harder than working out where to write the new text).

As far as the model answer goes, the philosophers do go through all the various states sequentially, but this can sometimes happen quickly. Quick to the point where you may not actually get to see it on the screen (i.e. if the "hungry" state is drawn on the terminal and then erased for the next state, before the terminal has had a chance to redraw itself — at 60 Hz or however fast).

Keywords: q7 , animation


Question 24 (2008):

Submission reference: IN1607

Hey there, several questions for you here, all of them q7 related!

Firstly, a while ago in the slides you mentioned using "Windows" (not the OS!) to output to certain areas of the screen as part of a test rig. How is this done (and what slides was is in!)? It seems like a necessary thing to do in order to do some nice animation effects.

Secondly - colour. I'm using ASCII art - is there a way to make this colourful in occam? How?

Finally - could you give us more information on how marks are distributed for this piece of coursework. Will there be marks for implementation (should I hold back until more or protocols/shared channels etc has been covered?) and code documentation? How much extra to you gain from making the animation 'nice'?

Answer 24:

The part about using 'windows' for debugging output is about putting your debugging output at the right place on the screen. If you're using PROTOCOLs to drive a display process, and/or a SHARED CHAN BYTE, you can engineer this in fairly simply. The main point is to stop debugging output being trashed by other screen-drawing code (which will probably happen if you just write messages to the top-level "screen" or "error" channels). For example:

  PROTOCOL DISPLAY
    CASE
      ...  existing cases
      debug; INT::[]BYTE            --* Debug message (counted array of BYTEs)
  :

  PROC display (CHAN DISPLAY in?, CHAN BYTE screen!)
    ...  existing code
    in ? CASE
      ...  existing tagged inputs

      INT mlen:
      [256]BYTE msg:
      debug; mlen::msg
        SEQ
          cursor.x.y (1, 24, screen!)
          out.string ([msg FOR mlen], 0, screen!)
  :

Or if you have the top-level "screen" passed down as a shared channel:

  PROC philosopher (..., SHARED CHAN BYTE debug!)
    WHILE TRUE
      SEQ
        ...  existing code

        CLAIM debug!
          SEQ
            cursor.x.y (1, 24, debug!)
            out.string ("This is a debug message in the right place*n", 0, debug!)

        ...  more existing code
  :

Regarding colour, yes, this will work provided you're using a terminal that understands the various VT220/ANSI escape sequences for this. There is some support for this in the shared-screen library that comes with KRoC, although that is fairly old now. Details on the actual things that need to be output to generate this can be found here: Wikipedia:ANSI escape code.

As a quick example, however:

  VAL BYTE FG.WHITE IS 37:
  VAL BYTE BG.BLUE IS 44:
  ...  other colours

  PROC set.fg.bg.col (VAL BYTE fg, bg, CHAN BYTE screen!)
    SEQ
      out.string ("*#1B[", 0, screen!)
      out.byte (fg, 0, screen!)
      screen ! ';'
      out.byte (bg, 0, screen!)
      screen ! 'm'
  :

  PROC display (CHAN DISPLAY in?, CHAN BYTE screen!)
    ...  existing code
    in ? CASE
      ...  other tagged inputs

      show.title
        SEQ
          -- draw a banner of some form
          cursor.x.y (2, 4, screen!)
          set.fg.bg.col (FG.WHITE, BG.BLUE, screen!)
          out.string ("Welcome to the display process", 0, screen!)
          screen ! FLUSH
  :

As far as marking is concerned, you will be marked on a combination of the output your solution produces, and the code that implements it. These are divided amongst the tasks that you have to complete, weighted according to relative difficulty, e.g. "adding a display process", "sensible reporting for the forks", etc. There are, however, a number of "bonus" marks available for solutions that go above and beyond the basic requirements. As a general rule, the model "q7" answer (simple text animation), if perfectly coded, can score 100%. A fully-featured animation (with characters walking around the screen, etc.), as we've shown you in the lectures and seminars, can tolerate some coding errors and still score 100%.

Keywords: q7 , colour , animation , ansi


Question 22 (2008):

Submission reference: IN1608

Hi, is it possible to make "screen!" shared? Or is there something we can do that offers the same effect?

Answer 22:

If you're using KRoC, then you can directly declare the top-level channels as being SHARED, for instance:

  PROC q7 (CHAN BYTE kyb?, SHARED CHAN BYTE scr!, CHAN BYTE err!)
    ...  code
  :

Which would give you a shared "scr!" (screen) channel, but unshared "kyb?" (keyboard) and "err!" (error) channels.

The Transterpreter does not yet handle shared top-level channels, but you can get the same effect through the use of a BYTE "id" process running in parallel with your code. For example:

  PROC new.q7 (CHAN BYTE kyb?, scr!, err!)
    SHARED! CHAN BYTE screen:             -- output end shared
    PAR
      --{{{  byte "id" process
      WHILE TRUE
        BYTE ch:
        SEQ
          screen ? ch
          scr ! ch
      --}}}
      --{{{  original q7 instance with shared screen channel
      q7 (kyb?, screen!, err!)
      --}}}
  :

Such a procedure can be added to the end of your existing q7.occ file, and becomes the new top-level process.

Keywords: shared-channel , q7

Referrers: Question 106 (2004)

2007

Question 59 (2007):

Submission reference: IN1407

Hi, I am working on the inheritance protocols for the dining phil assignment and the following code:

  PROTOCOL SECURITY IS INT:

  PROTOCOL PHIL IS INT; [28]BYTE:

  PROTOCOL FORKP IS INT; [19]BYTE:
  
  PROTOCOL REPORT EXTENDS SECURITY, PHIL, FORKP:

crashes the transterpreter. I get this message:

  Warning: Changed source file saved.
  Compiling: q7.occ
  Fatal-occ21-q7.occ(61)- unknown tag N_SPROTDEF in pi_valcheck

Any ideas what I am doing wrong?? In the lecture notes there are only examples of inheritance using CASE protocols. Am I only allowed to use those? Thanks for your help

Answer 59:

In the shared-etc slides, slide 28 (the first one on this topic) says: "A variant (or CASE) PROTOCOL can extend previously defined ones". So, yes – I'm afraid inheritance is only defined for CASE (i.e. variant) protocols. One protocol extends another by adding new variants. We have to have the tags to distinguish between the different variants of message.

By the way, please don't put strings (e.g. [28]BYTE) into your report protocols. For one thing, occam-pi doesn't support strings very well (until we start working with mobile arrays, whoses sizes are dynamic). For another, constructing particular strings for the report messages should not be done by the processes generating those reports. Do that separately – e.g. in a display process receiving those reports. This separates two concerns: the logic of the system making the reports and the presentation of the reports.

Keeping these separate means we can change the look-and-feel of the running system (e.g. to introduce all sorts of animation) without touching the logic of the system. De-coupling such things is simply good (software) engineering.

But we do apologise for the compiler crashing on your (illegal) code. That won't happen with the new compiler(s) in development! The Transterpreter and KRoC currently share the same compiler. Downloading KRoC delivers full sources for the compiler. We are always grateful for any fixes, :).

Keywords: q7


Question 58 (2007):

Submission reference: IN1406

Hi, could you tell me if it is possible and if so how to: initiallise an array of strings with values in it ie something like this

  VAL [][]BYTE strs IS ["hello","fish","mango"]:

i can't work out how to do it.

Answer 58:

In a 2-dimensional array, all sub-arrays must have the same dimension. Here, your individual strings are of different sizes. See Question 33 (2006) and related questions.

Keywords: q7 , strings


Question 57 (2007):

Submission reference: IN1405

Hi, I am doing the dining phil assessment and I am getting some wierd behaviour out of the philosophers method. in the following code:

  WHILE TRUE
    SEQ
      CLAIM output!
        out ! ID; 't'
      ...  more code
      IF
        ID = 0
          SKIP
        TRUE
          STOP
      ...  more code
      CLAIM output!
        output ! ID; 'e'
      ...  more code

the first output of ID (which is a parameter) provides the correct values (0-4 for specific phils). I have proved this by putting the 'STOP' test above the first claim. however, the subsequent outputs are always 0 an i cannot get the 'STOP' test to work, i.e. it never stops. this leads me to believe that ID is being changed somehow when it is sent down the channel. can you give me any tips?

(all of the output channels work correctly, its just that the value of ID changes some how)

Answer 57:

This seems a little odd.. If you're compiling in "stop" error-mode, then a process that goes STOP will just quietly stop, and leave other processes running. In "halt" error-mode (which is the default), a process that goes STOP will shut-down the whole program (and cause it to exit with an error message). The behaviour you describe (correct initial outputs, but then only ID 0 reported), sounds like something in "stop" error-mode (i.e. all but philosopher 0 die quietly). Putting a STOP above the first output in "stop" error-mode would induce deadlock, which the run-time detects and exits with an error message. If the type of ID is VAL INT (presumably it is), then it's not going to change, unless something has gone very wrong with your KRoC/Transterpreter installation.

But perhaps you are saying that you have 5 different philosopher processes, one for each ID? In which you have tests for different correct values (0-4 for specific phils)?? That would be very silly though ...

So, with just one philosopher PROC and five instances (each with a different ID value passed to them), the one with ID 0 will survive your test and the other four will STOP, crashing the system.

If the type of ID were a mobile something, and the output channel carried mobiles, then ID could be subject to change (but then couldn't a be a VAL INT parameter). Otherwise, there is no way sending the value of ID down a channel will change what is in ID, regardless of whther it is a VAL.

We really can't tell what your problem is with the code snippet you posted, I'm afraid. You could try mailing us directly ...

Keywords: q7


Question 56 (2007):

Submission reference: IN1392

Within the philosopher PROC, i've implemented a looping function to report the state to the display PROC (via a shared-channel), then pause for some amount of time:

    SEQ i = 0 FOR 5
      SEQ
        CLAIM report!
          report ! thinking; id; i
        pause (second)

What i want to do though is wrap this in another PROC, however am stuck at how to go about relaying what the state is (the report has a CASE protocol type) and the state i want to relay is the "thinking" or any of the others i have I thought of have the added PROC to recive a VAL INT, to which then uses that over a CASE of IF seq, though this just would have duplicated code of the above.

Is there any way to pass a PROTOCOL tag to a PROC parameter, similar to a VAL in occam-pi?

Answer 56:

No, you cannot have data items of PROTOCOL types. This is because the data transported by the variant (CASE) protocol depends on the case -- which would require either UNION types or var-args PROCs, neither of which we currently have in occam-pi. I'd question whether or not wrapping up such an output in a PROC is sensible anyway, but you could use VAL INTs to indicate which tag you're wanting to output (and make sure the PROC gets the necessary information for any particular case).

If you're just after code separation, do a separate PROC for each type, e.g.:

    PROC report.thinking (...)
      ...  code
    :

which you can declare inside the body of the philosopher process.

Keywords: q7


Question 55 (2007):

Submission reference: IN1391

I have a question about this previous question/answer: Question 61 (2006).

I'm a little bit confused about this answer, are we able to put in another process into "secure.college"? Or are we supposed to have our reporting process communicating from inside the philosopher? If we are supposed to call the reporting process from inside the philosopher how would it be possible to wire the reporting process to the screen as it would be outside the main q7 process?

Answer 55:

The point about that was not to interfere with the collection of processes inside "secure.college", but rather re-wire them in a way that allows your display process to live 'outside' the secure-college process. Thus, the top-level Q7 process will run the modified "secure.college" and any "display" process (connected to the screen) in parallel. To get information from the individual philosophers/forks to the display process will require adding channels (or a single shared channel), and those channels must pass through "secure.college" (i.e. they will appear in its interface).

Keywords: q7


Question 48 (2007):

Submission reference: IN1374

Hi, I've started wiring up the phils problem, and have most of it working. I plan on wiring it up normally and then switching to shared channels if I get time.

I've just come to wire in the forks and keep introducing deadlock :(

Because the two forks are picked, and done so in parallel I want to do something like this:

    ...  code omitted

That is read one fork's message then get the next one; or at least that's what I want it to do. What am I doing wrong here?

Answer 48:

You have four nested ALTs!! Nothing with that complexity is needed.

I'm assuming this code is in your display process – the one at the receiving end of all the report channels from the individual players (phils, forks and security guard) within the college. This display process should be pretty dumb – just displaying stuff whenever any report arrives. It should not be enforcing any ordering on the reports it receives (e.g. read one fork's message then get the next one). It should just receive a report (e.g. fork 2 has been picked up by the philosopher on its right) and display that fact to anyone looking at the terminal window. It could then receive a report about another fork ... or from the security guard ... or from a philosopher ... and display whatever is being reported.

It's up to the college processes to ensure illegal reports don't arrive ... like a philosopher reporting that it is thinking and, then, eating without going through a hungry state (when it may be held up by security) ... or a fork being held by two philosophers at the same time. The display just displays whatever is reported!

If all the (11) report channels belong to a single array, all the display process has to do is a single replicated ALT over all the elements. It knows which type of report it is (from the opening tag in the message protocol) and from which philosopher or fork it is (by the index of the element of the array on which the message arrived – e.g. 0-4 are from philosophers, 5-9 from forks and 10 is from the security guard).

If you use a channel with SHARED writing-ends, then the display process just listens on that one channel – no ALT is needed at all! The message protocol will need enriching so that the phils/forks also report their identity (just an INT) after the report type tag – but that's easy ... once you have worked out how each phil/fork gets to know its identity, which the starter code file (q7.occ) doesn't provide.

Keywords: q7


Question 46 (2007):

Submission reference: IN1373

Would it be possible for you to make another sheet regarding the philosophers assessment? I have found it quite useful to have one for cylons.

Answer 46:

Again, I'm sorry! I think there is enough information in slides 3-60 from applying, in the q7.occ starter file and from the discussions in your seminar groups. You are also advised to browse through the wealth of material in the Anonymous Q&A repository – check out q7 and random in its keyword index.

I'll say this again ... since it's really really helpful: check out q7 from the keyword index of the Anonymous Q&A repository!

Keywords: q7


Question 39 (2007):

Submission reference: IN1365

I feel that the amount of coursework for this module is much more than any other module I've taken.

The assessments are getting much harder and overlapping two really doesn't help. Why couldn't the two final ones have been combined into one assessment testing both skills?

It might have been ok having two assessments from one module at the start of the term, but being a final year CS student, the deadlines regarding final year projects and other modules are building up.

Answer 39:

The final two assessments for this module are deliberately open-ended. We want to see what you can do – above a minimum requirement – and this gives you a chance to be creative. However, you will still get very good marks if you do the minimum.

The two assesments test different skills. The Cylons is about the logic for planning robot movement in response to a particular set of sensary data. It is embedded in a multi-robot graphics animation, the code for which is fun and effective but does not need to be understood or modified. The philosophers exercise is the opposite – we give you all the control logic and you are invited to construct a simple animation that shows what is happening. Testing both such skills at once would be daunting.

Each assessment has been given four weeks, with an overlap of two weeks when both can be being developed. You are not expected to work for four weeks on each of them! The long periods enable you to schedule the work in a way that works best for you.

Having said that, we do appreciate that final year students may have a special problem because their final year projects are due in week 23 (which is in the middle of the two deadlines for our final two assessments). So, for final year students, we will be relaxed about our deadlines. An announcement on this will shortly happen.

Keywords: cylons , q7

Referrers: Question 41 (2007)

2006

Question 103 (2006):

Submission reference: IN1174

Did we get additional marks for using shared channels on the dining philosophers assessment?

[Ed: this question has been combined with the following for a single answer.]

There is not much feedback on my dining philosophers assessment, I did not even know what the mark was out of until my friend told me, I would like to know what I lost marks on... seen as my dining philosophers worked and had additional features within it. Who can I ask about this?

Answer 103:

Using shared channels simplifies the solution, which may result in a higher mark. Extra marks were allowed for shared channels, protocol inheritance etc., but markers had freedom to award other marks for specially nice things. Quality (e.g. simplicity, no repetitive lengths of code differing only with magic numbers) and animations beyond the minimum requirement were the main sources of extra marks. Marks over the maximum were not allowed though! Extra marks usually compensated for minor ommisions/errors in otherwise good solutions – resulting in a maximum score.

I'm sorry if your returned script contained little feedback. Some contained a great deal! Below is the marking scheme and guidelines given to the markers, which should let you see how your marks were awarded. If you think your marks do not represent a fair assessment of your work, please contact me (phw@kent.ac.uk) directly. Thanks.

    
            =====================================================
            Dining Philosophers Animation - Marking Scheme (2007)
            =====================================================
    
    This year, they do not have to submit diagrams if their solution is the
    standard one (i.e. 11 reports channels from the college to a multiplexing
    display ... or 1 SHARED report channel from the college to a display).
    
    If they have done something else, they were asked to provide a diagram
    (e.g. a GIF, JPG etc. image in their submission directory or hard copy,
    could be hand-drawn, handed in to CAS).
    
    However, it would be harsh to penalise those who have something more ambitious
    (e.g. with extra animation processes) but a poor diagram.  So, treat those
    diagrams as aids to understanding their system - but no penalty if no diagram.
    Give additional marks for more ambitious animations.  The basic animation
    (run ./a7 on raptor at /proj/ofa/631/answers/) is all they need for full marks.
    
    This year, I never got around to specifying any keyboard interaction - e.g.
    for setting the random number seed to a known start value ... or for freezing
    the display.  Award extra marks if any do this.
    
    Here is the breakdown:
    
      4 : decent PROTOCOL declaration(s) - deduct 2 marks if no commented
          explanation of any component fields of, for example, tagged variants.
          CHAN INT report channels, reporting VAL INT *named* codes, are OK
          but only get 3 marks.
    
      7 : the philosopher PROC - roughly 3 marks for random timeouts when
          thinking/eating (and for getting/setting the seed correctly and
          uniquely) plus 4 marks for making sensible reports.  Note: the
          seed should be set *once* before starting the philosophers and
          passed to each philosopher (who adds his-her id number).  I gave
          them a random number warm-up PROC in the anon Q-and-As (Q55) that
          they should use - but no penalty if they don't.
    
      3 : the fork PROC - for adding sensible reports.
    
      3 : the security PROC - for adding sensible reports.
    
      4 : the code for the networks - 2 for the modified secure.college (with
          all the report channels) and 2 for the top-level network code.
    
      9 : the display PROC - 2 marks for some sensible initialisation;
          6 marks for everything else.  This year, we also never got around
          to making them work out fair alting, :(.  Extra marks if they did,
          though this is only relevant for a report array.  Award extra marks
          if they used a SHARED channel, and more if they used PROTOCOL
          inheritance (so that the phils, forks and security had their own
          protocol and the report channel itself combined all three).
    
    ----
     30
    ----

Keywords: q7 , coursework

Referrers: Question 30 (2008)


Question 75 (2006):

Submission reference: IN1092

I asked Question 71 (2006) a few minutes ago, it was very helpful. I've altered my program and now I have an output, I'm using one shared channel. So far the security guard and the phils are sending information down it. Phils 0 and 1 seem to be getting all the attention of the security guard now though.

I can't see how my display proc would cause this discrimination but thats the only proc I've added, and I haven't even altered anything else that much yet!

Sorry to include so much code, but I can't see how else to show you what's going on ...

    ...  PROTOCOL status

    ...  PROC display (CHAN status in?, CHAN BYTE out!)

    ...  PROC q7 (CHAN BYTE keyboard?, screen!, error!)

where q7 runs the college in parallel with a display process connected by a single channel carrying the status protocol, shared by all the college processes at the writing end.

Answer 75:

Sorry, I've edited out most of your code in your question. Your system now has a good structure. I don't know why you aren't seeing phils 2 through 4 getting past security – you didn't submit all their codes. But we couldn't answer it even if you had. I'm afriad this is not a debugging line ...

Keywords: q7 , coursework


Question 71 (2006):

Submission reference: IN1086

I'm having some difficulty outputting what's going on, I've tried using the below code to output what the philosopher is doing and what philosopher is doing it. However, currently nothing is coming out.

I have three constant which are thinking, eating and waiting of int values 1, 2 and 3, these ints are set in the philosopher PROC then output to print.stream along with which philosopher it is (i). Can u give me any help with this please?? :(

    PROC secure.college ()
      [5]CHAN BOOL left, right, up, down:
      [5]CHAN INT status:
      [5]CHAN BYTE screen:
      PAR
        security (down?, up?)
        PAR i = 0 FOR 5
          PAR
	    philosopher (left[i]!, right[i]!, down[i]!, up[i]!, status[i]!)
	    fork (left[i]?, right[(i+1)\5]?)
	    print.stream (10000, status[i]?, screen[i]!, i)
    :

Answer 71:

Stop, stop, stop, stop using print.stream ... that prints a single stream of integers to a single screen channel ... it was only ever of use in questions 1 and 2 ... it has absolutely no use for this assignment!

Your secure.college process above has no (channel) parameters – so there is no way it can get any results out anywhere, let alone to the screen.

You have attached status channels carrying integer codes: one from each philosopher – that's reasonable (though a variant protocol would be better). But each of these status channels is then connected to its own print.stream process which outputs to its own screen[i]! channel. That tries to send ASCII text down that channel – but none of those channels are connected to anything! Thus, each print.stream blocks which means that each philosopher blocks ... which means the whole system deadlocks (the forks and security are waiting to hear from philosophers).

As shown in slide 60 from applying.ppt and discussed in the lecture and in seminar groups, those status channels should be external output channels (i.e. parameters) from your college and there should be a display process, running in parallel with the college, that multiplexes in all the status channels and generates (animation) text to the screen. You also need 5 more status channels from the forks in the college, plus one more from the security guard.

Keywords: q7 , coursework

Referrers: Question 75 (2006)


Question 66 (2006):

Submission reference: IN1060

I'm just trying to work out the shared channel business and I have come up with a shared channel array of 26 'CHAN INT's. 15 for the philosophers: 1 for thinking, 1 for sitting and 1 for eating therefore 3 states * 5 philosophers = 15. 10 for the forks as two states (left, right) * 5 philospohers = 10. Finally 1 for the security to report on. Which ever channel I get an input on I then know what has happened and who by, is this a good way of doing it?

Answer 66:

It works, but I wouldn't say it's a good way. There are two pieces of information you're trying to communicate here: who is doing it, and what it is they're doing. Probably best to keep these separate. Having a single channel for each of the philosopher, fork and security processes (11 in total) makes sense — that tells you who is doing it. As for what they're doing, using a tagged-protocol would make sense — this makes that information explicit, and definitely makes it easier to modify — without having to rewire other bits of the network.

By the way, the forks have 3 states (on-the-table, picked-up-by-left-hand, picked-up-by-right-hand) – not 2.

Keywords: q7 , coursework


Question 65 (2006):

Submission reference: IN1059

Does the display process only need to take one array of channels from all of the the process that are reporting to it? If so then I assume this channel will be shared among the philosopher, fork and security procs?

Answer 65:

Yep, that's pretty much correct. But your second sentence is inconsistent with your first. Your "this channel" suggests splitting a single channel up amongst the various processes; whereas you talk about an array of channels in the previous sentence.

What you should do is give each of the philosopher, fork and security processes a single channel from within an array of channels – see slide 60 from applying.ppt. As described in the lectures, you can do it with a single channel – and it's much easier (especially for the display process, which then only has one channel to deal with). But that means using a SHARED channel and CLAIM blocks, as presented in slides 3-26 of shared-etc.ppt.

Note: there is some stuff relating to shared-channels in previous anon Q+A, but these use the old-style which involves SEMAPHOREs and explicit claim and releases (not particularly nice, but these were before the days of mainstream occam-pi).

Keywords: coursework , q7 , shared-channel

Referrers: Question 68 (2006)


Question 64 (2006):

Submission reference: IN1054

Hi, I'm working on the dining philosophers assessment but I'm not doing too well. I have attended the classes, seminars and most of the lectures but am still struggling. I understand what we are supposed to do and have a rough idea of how to do it, but i just don't know where to start. Can you give a rough outline of how to go about it, so i know what to do and in what order?

Also can you explain the following PROC? I understand the others given in the q7 starter file, but this one confuses me:

  PROC secure.college ()
    [5]CHAN BOOL left, right, up, down:
    PAR
      security (down?, up?)
      PAR i = 0 FOR 5
        PAR
          philosopher (left[i]!, right[i]!, down[i]!, up[i]!)
          fork (left[i]?, right[(i+1)\5]?)
  :

Answer 64:

Starting with your second question, the secure.college process sets up a network of parallel sub-processes. If you look at the relevant lecture slides (available from the module directory on raptor, slides 36-39 of applying.ppt/pdf), you'll see a picture of the process network which this creates. It creates a PAR network containing one security and five each of philosopher and fork. Each philosopher has two channels connecting it to the security process, and two channels connecting to the forks on either side. The modulo operator (\) is used to wrap-around the channel connections -- e.g. the last fork (where i+1 is five), needs to connect to the first philosopher (the modulo 5 sets it to zero, which is the same index as the 0th philosopher's 'right[i]' channel (because i is zero).

With regards to starting the assessment, I'd begin by creating an outline for a display process which will take input from the various philosophers, forks and security (via an array of channels), and generating output to the screen. I would suggest having the display process outside of secure.college — and running in parallel with it, so there will be some channels connecting secure.college to display.

The next step would involve allowing the various philosopher, fork and security processes to output to the display. If you have modified secure.college to have a channel-array parameter, this means distributing those channels to the various processes — i.e. adding single-channel parameters to the processes which will generate output to display. From there, get those processes to generate outputs, which the display process receives. It might be sensible to start with simple INTs being reported to display, but to do any serious level of reporting you'll proably want to use a tagged-protocol.

Before coding, it's wise to start with a process-network diagram of what you're trying to code — design first, then implement! The wealth of q7 related questions from previous years will also be helpful.

Note: you say you have attended seminars and lectures. All the above has been presented – in detail – in the seminars and lectures.

Keywords: q7 , coursework


Question 63 (2006):

Submission reference: IN1051

Dear Sir, I've been trying to introduce a pause into my program but I'm getting an incorrect indentation error. I know I must have made simple mistake somewhere, but i can't understand why and where this error is. I'm just wondering if you could give a hand in getting rid of this error.

  PROC philosopher (CHAN BOOL left!, right!, down!, up!)
    ...  local variable declarations
    SEQ
      ...  local variable initialisation
      WHILE TRUE
        --{{{  think
        SEQ
          ...  random delay code
        --}}}
        --{{{  get permission to sit down
          down ! TRUE
        --}}}
        --{{{  pick up the forks
        PAR	    <----------- Error-occ21-q7Edited.occ(53)- incorrect indentation
          left ! TRUE
          right ! TRUE
        --}}}
        ...  more stuff
:

Answer 63:

Somehow you've managed to damage the existing contents of the WHILE loop. Removing the opened fold comments from your loop body leaves:

        WHILE TRUE
          SEQ
            ...  random delay code
	    down ! TRUE
          PAR
	    left ! TRUE
	    right ! TRUE
          ...  more stuff

The error on the PAR is because you don't say whether this should run in parallel or in sequence with the SEQ above it. The problem is broken re-indenting of code, e.g. that PAR should be part of (indented inside) the SEQ, not alongside it.

Look again at the starter file code for philosopher (with all the folds open) and compare it with your code – there's no reason for code inside a fold to start at an indentation level different from the fold markers (which is what's happened in your code).

Keywords: q7 , coursework


Question 62 (2006):

Submission reference: IN1037

Hi, I've just got started on the assessment but I've come to a problem. Some of my code in my display process is:

    [11] CHAN INT x:
    WHILE TRUE
      ALT i = 0 FOR 11
        in[i] ? x[i]
	  print.stream(0, x[i]?, scr!)

As you can probably tell, I'm just trying to get the outputs working first before I make the animation. So, I'm printing using print.stream for now to debug.

However, the fourth line above is causing this error:

    Error-occ21-q7.occ(145)- I/O list item 1 does not match protocol

I can't work it out!

Answer 62:

The array 'in' is presumably a channel array from the display process header. You should input INTs from CHAN INTs — your code is currently attempting to input into another channel (x[i]), which doesn't make sense; hence the error regarding protocol mismatch. You probably meant for x to be an array of INTs – not CHAN INTs!

However, your use of print.stream is very wrong. That process runs forever, consuming numbers and printing them. So, after receiving its first input from channel in[i], it runs print.stream forever taking numbers from that same channel – assuming you plugged in that channel and not x[i], which is either a channel (as in your code, but which is wrong as there is no process outputting to it!) or an integer (which it should be, but is illegal here!). No data from any other channel would ever be taken.

I've no idea what numbers are arriving on your in[i] channels ... but if you just want to print them, just print them:

   ALT i = 0 FOR 11
     INT value:
     in[i] ? value
       SEQ
         out.int (value, 0, scr!)       -- print the number
         out.string ("*c*n", 0, scr!)   -- carriage-return and line-feed

Note that the above sequence prints one number (see out.int). Using print.stream would lock this process in to the channel and print the whole infinite series of integers that arrive.

Note further that it only makes sense to use an array of values (e.g. [11]INT x:) if you have some need to keep the last reported state from each channel. If you intend to handle them on an individual basis, just use a single locally declared variable (like value in my snippet).

I also question the use of the magic number 11 all over the place — name this as a VAL INT constant at the top-level somewhere.

Keywords: coursework , q7 , out.int


Question 61 (2006):

Submission reference: IN1058

Would I be right in saying that the only way to identify which philosopher is doing what is to do the reporting after this line:

  philosopher (left[i]!, right[i]!, down[i]!, up[i]!) 

in secure.college? My rationale being that this is the only way to identify each channel as we have access to the 'i' variable.

Answer 61:

No. It doesn't make much sense to try and do reporting in SEQ with the philosopher instance (which is part of a network of parallel processes). The philosopher process has a WHILE TRUE loop, so it won't terminate – nothing following in SEQ after it will ever run. Changing that loop into one that terminates means placing another loop around the philosopher invocation and your reporting process. Your philosopher then comes into existence and terminates repeatedly. This is not a nice way – it makes the code hard to understand (and is the sort of thing you normally end up programming C/C++/Java/etc.).

The only process which knows what a philosopher is doing currently is the philosopher process. Keep the philospher reports there. If you want each philosopher to be able to identify themselves, simply pass its index, i, as a VAL INT parameter to the philosopher procedure. You'll probably need to add some other things too – like a report channel! There is no way for the philosopher to report its actions at present (and deducing it from interactions with security and the forks alone would be complex – and probably wrong).

Keywords: coursework , q7

Referrers: Question 55 (2007)


Question 60 (2006):

Submission reference: IN1039

Hi! My code won't compile. The compiler says its outputting to variable "doing" in parallel, which it is ... is there a way to avoid this?

I could use 4 different variables, but that seems wasteful ... any suggestions? Here's the relevant bit of my code (which gives the error: 'doing can't be output in parallel')

      --{{{  pick up the forks
      PAR
	left ! TRUE
	doing ! 2
	right ! TRUE
	doing ! 3
      --}}}

Thanks!

Answer 60:

For any specific channel, occam-pi only allows one process at a time to output to (or input from) it. For normal channels, this means that only one process in a PAR block is allowed to have the output end (respectively, input end). In the code fragment in your question, there are 4 processes running in parallel – and 2 of them are outputting to the same channel. The compiler is right to complain!

I suspect that you really meant your code to be:

      --{{{  pick up the forks
      PAR
	SEQ
	  left ! TRUE
	  doing ! 2
	SEQ
	  right ! TRUE
	  doing ! 3
      --}}}

so that the doing reports are sent only after the relevant fork was obtained. However, that still leaves 2 processes running in parallel and outputting to the same channel – still illegal!! But picking up the forks must be done in parallel.

To do the above correctly, you would need a doing.a and a doing.b channel so that the reports could be made in parallel. Now, each philosopher has 2 report channels that must be connected to your display process. Alternatively, if all your philosophers, forks and security guard reported through a SHARED output channel, then the above code would be legal (provided, of course, the doing channel was CLAIMed first). [I've no idea what you might mean by using "4 different variables" to solve this?]

However, you were advised in your seminar groups not to bother reporting the picking up, or putting down, of forks by the philosphers. Much easier is for the forks to report their being picked up and put down. Hopefully, you are doing that ... in which case, there is no need to program the philosophers to duplicate that information. Problem deleted!

Keywords: q7


Question 59 (2006):

Submission reference: IN1038

I have the following report process, which is linked to the screen output channel. I want to be able to output the value of the INTs coming in on up and down, but I seem to have a casting issue.

    PROC report (CHAN INT up?, down?, CHAN BYTE output!)
      WHILE TRUE
        ALT
          INT a:
	  up ? a
	    output ! BYTE a
          INT b:
	  down ? b
	    output ! BYTE b
    :

As the screen output only accepts bytes, I have attempted to cast the integers. But when this process is run, the output is simply a bunch of smilies :-) ...

Is there is simple casting issue or do I have to attack this from a different angle?

Answer 59:

If the arriving INT were, say, 65 – then, casting it to a BYTE and outputting it to a channel connected to the main screen channel would print the symbol 'A'. Further, if the arriving INT were, say, 7 – then, casting it to a BYTE and outputting it to an channel connected to the main screen channel would cause the terminal to bleep (since 7 is ASCII code for BELL). Neither of these is probably what you wanted!

If the arriving INT were, say, 65 and you wanted to print the symbols "65" – then:

	    out.int (n, 0, out!)

would do the trick (assuming n is a variable holding the value 65 and out! is connected to the main screen channel).

But I don't recognise this report process in connection with the dining philosophers animation? What are you trying to do here??

Keywords: q7 , cast , out.int


Question 58 (2006):

Submission reference: IN1032

Hello, currently I have:

    PROC reports (SHARED CHAN MESSAGE out!)
      ...
    :

    PROC display (CHAN MESSAGE in?, CHAN BYTE out!)
      ...
    :

But I dont know how to connect the reports from the colleges to the reports process.

Answer 58:

I don't know what your reports process does or is for? It's the college and its sub-processes that should be give this channel – and the sub-processes (claim and) use them. See Question 57 (2006) for more clues.

Keywords: q7


Question 57 (2006):

Submission reference: IN1055

Hi, I am using a variant protocol MESSAGE for carrying messages and I have a display process that inputs from only one channel that carries MESSAGE. In the header of each process within the college, there is a SHARED CHAN MESSAGE report! parameter. In each college process, e.g. the philosopher, I report one of the states like this:

    CLAIM report!
      report ! thinking; id

But when I am running it, it does not print out anything! I really don't know what's wrong with it.

Answer 57:

Everything you have described looks right. Check your wiring. The college process itself must take a shared report! channel parameter, which it passes on to all its sub-processes. The actual report! channel, shared at the writing end, must be declared before the PAR setting up the college and display processes – and, of course, the right ends plugged into them. Finally, make sure your display process really is connected to the outermost screen channel.

Keywords: q7

Referrers: Question 58 (2006) , Question 69 (2006)


Question 56 (2006):

Submission reference: IN1031

Hi, I got a process:

    PROC display ([]CHAN MESSAGE in?, CHAN BYTE out!)
      ...  code just dealing with phil messages (edited out)
    :

which reads an array of variant protocols named MESSAGE.

I am just wondering: do I need another process that reads the reports from the philosophers, forks and the security, multiplexes them and outputs an array of variant protocols named MESSAGE to the display process. Thanks.

Answer 56:

No. Connect all report channels (in a single array) to your display process. Your MESSAGE protocol should define all messages from all agents (i.e. phils, forks and security). Your display just needs expanding to deal with all varieties of MESSAGE.

Keywords: q7


Question 55 (2006):

Submission reference: IN1029

Am I defining my random numbers seeds correctly?

    PROC philosopher (VAL INT id, CHAN BOOL left!, right!, down!, up!, CHAN INT state!)
      INT waiting.time, seed:
      TIMER tim:
      SEQ
        tim ? seed
        seed := (seed >> 2) + (id + 1)
        WHILE TRUE
          ...
    :

The philsophers all seem to start off with the same thinking time? So I'm a bit confused as to what I've done wrong.

Answer 55:

All your philosophers will start in the same few microseconds – possibly all in the same microsecond! So, all get the same initial seed value from the timer. That is shifted right by 2 bits, which makes it positive but also makes it even more likely the result (so far) is the same. Finally, the philospher's id, plus 1, is added which makes it very likely they all go into their loops with different seeds. However, if philosophers with lower ids were scheduled after those with higher ones, they could still go into their loops with the same seeds.

To ensure they start with different seeds, compute an initial seed just once (using the timer, as in your code above) and before starting any philosophers (e.g. before starting the whole college). Pass this same initial seed into each philosopher and get them to add in their id number. Now, each philosopher is guaranteed to start its loop with a different seed.

However, random number generation is a black art. Starting from consecutive initial seeds, it takes some of them (like the cheap-but-fast one used by the course library's random function) a little while to diverge. So, I'm not surprised they all start off with the same thinking time.

To combat that, warm up your generator before first using it! Here is an example routine to do that:

    PROC warm.up.random (VAL INT warm.up.count, INT seed)
      SEQ i = 0 FOR warm.up.count
        INT dummy:
        dummy, seed := random (42, seed)
    :

A warm.up.count of 1000 will suffice.

Keywords: q7 , random

Referrers: Question 29 (2008) , Question 33 (2007)


Question 53 (2006):

Submission reference: IN1023

I keep getting a STOP error when I try to run my animation, it works for about a second or two and then gives me the error. Is this deadlock? I don't remember getting a STOP error when getting deadlock in the classes.

Answer 53:

No, it's not deadlock – that would give you a deadlock error.

Please browse through the questions and answers from "q7" in the keyword index. The best help for this is probably Question 70 (2000), which also tells how to get more information on the line causing the error – unfortunately, you need the Linux occam-pi compiler (kroc) for this (available within your VMWare linux environment).

Keywords: q7 , stop


Question 52 (2006):

Submission reference: IN1021

My philosophers currently teleport between the table and the office. Will I lose marks for this if I stick with it, and say its a magic college?

Answer 52:

No – that's fine! That's all the minimum animation standard (Question 46 (2006)) requires for full marks. But letting them move smoothly in parallel is not hard and very satisfying – you will need an extra process between each mover (philosopher or fork) and the display process. Plus a way to let each phil/fork know when its movement animation is complete, as mentioned in the last sentence of the answer to Question 51 (2006). That requires a further small modification to your phil/fork processes. Actually, if you find out about the extended rendezvous (slides 52-61 of shared-etc), an explicit acknowledgement back to the mover is not needed, :).

Keywords: q7


Question 51 (2006):

Submission reference: IN1019

I have a printing process which uses this:

    ...  code hidden

Which I presume would be fair ...? If so, I still get some inconsistencies, such as the security guard saying there are 4 seats taken, where as the dining table only has 2 people 'sat' at it? Is there a way to get rid of this problem, or is it just random that problems like this pop up and I have no way to stop it?

Answer 51:

First, please note the third paragraph at the top of these pages. You included far too much and too specific code for general discussion.

Having said that, you are trying to set up a fair alt over all your report channels - see the note at the end of the answer to Question 43 (2006) (and the whole set of questions on this found from the keywordindex under "fair-alt"). Your code is fair between the security guard and the general set of philosophers and forks, but there is strink priority between the philosophers themselves (the lowered number ones always being preferred) and bewteen the forks themselves. So, your code is clever ... but not fully fair.

It would be much easier to be fair if you have only one array of report channels (11 altogether – 5 from the phils, 5 from the forks and one from security). I note you are using PROTOCOLs for the report channels. Great! Naturally, your PROTOCOL for the phils is different from that for the forks and that for the security guard. To have all these channels in a single array, there are two ways. Either merge the three PROTOCOL definitions into a single PROTOCOL (which is not nice semantically). Or read on to learn about variant protocols (which we will do in the next lecture) and, to be really cool, shared channels and protocol inheritance (in shared-etc.ppt and which comes next).

However, for this exercise, there is no need to set up fair alting by the display process on its report channels – see the fourth paragraph in the answer to Question 43 (2006).

Regarding your inconsistency problem, I'm afraid that this is not an inevitable problem resulting from arbitrary scheduling of your processes – your code is in error. That problem doesn't arise in any of the example executables mentioned in the answer to Question 46 (2006). So long as your security guard, phils and forks are wired directly to your display process (i.e. not routed through some other processes) and so long as your display process outputs directly to screen channel, your inconsistency cannot arise. That's all you need for the minimum animation standard (Question 46 (2006)) that gets full marks. If you are doing something fancier, you must find a way to ensure that when a college process makes a report it waits for confirmation that the report has been fully animated before proceeding (e.g. by waiting for some acknowledgement).

Keywords: q7

Referrers: Question 52 (2006)


Question 50 (2006):

Submission reference: IN1018

Why is it some PROCs are commented and some aren't in q7? I want to put comments in so I don't get confused, but I'm not sure which style to use ... :(

Answer 50:

Only two styles of comment are in the q7.occ starter file: fold comments (around entire PROCs and special chunks of code) and line comments (annotating particular lines).

To appreciate the fold comments properly, you need to use a folding editor – such as vim or gvim. Look up "folding" in the keyword index for these anonymous questions.

As far as occam-pi is concerned, there is only one kind of comment: everything from "--" to the end of the line is a comment. Both fold and line comments obey this – the former being a line comment on an otherwise empty line.

Without a folding editor, the fold comments around entire PROCs are a nasty distraction. So, only add them in your script if you are using a folding editor! The fold comments around special chunks of code do supply useful information, even when not using a folding editor. So, please copy that style.

For the ambitious, find out how to use the occamdoc tool. See the link, "occam-doc documentation" from this module's web page. Of course, this is not necessary to obtain full marks in this assessment!

Keywords: q7


Question 49 (2006):

Submission reference: IN1016

Hi, I have a few questions! How can I use the random function? This doesn't work:

    SEQ
      ...  stuff
      rr := random (800, 666)
      pause (rr)
      ... more stuff

nor this:

    SEQ
      ...  stuff
      pause (random (800, 666))
      ... more stuff

How do I get the number random is giving out? And what's with the second number (the seed)? Seems a bit loopy to me, why not just have random (upTo)? Doesn't the seed just complicate things? I don't get it! Thanks very much!

Answer 49:

This is being explained in your seminar groups. However, all the information can be found in past answers to these anonymous questions. Before asking, always check through the keyword index page!

In this case, there's loads of information about random. You have to get your head round the very useful concept of a function returning more than one result. The answers also explain why we need a seed variable and how to initialise it and operate it when we use the random function. A random number generator without a seed is like a butterfly without wings ... it won't fly very far.

Note: Java protects the user from having to operate the seed when computing the next random number – but you still need to know about initialising it. We could do the same very elegantly in occam-pi with a random number process (not function) running concurrently with the processes that need it. Probably, we should include such a process in the course library. The reason we haven't, so far, is performance. Random numbers tend to be needed heavily in complex modelling systems. Indeed, most of the compute time can be spent just computing random numbers! Using a function, rather than channel communication with another process, has significant speedup for such models. But that's not relevant for initial learning exercises.

Keywords: q7


Question 48 (2006):

Submission reference: IN1014

How do I make a function that returns nothing? I want to make one that draws a queue of people waiting to enter the dining hall.

Answer 48:

We haven't done functions yet in occam-pi! Functions in occam-pi are like functions in mathematics (or functional programming). Their only purpose is to return something – they can perform no side-effects (like communicating over a channel). See the PPT/PDF shared-etc, slides 88-93, if you want to read ahead.

I can only think that you mean a procedure – i.e. a PROC. These don't return anything and their only purpose is to cause side-effects (like communicating over a channel).

An occam-pi PROC that runs for a long time and is invoked as a component in a PAR construct ... is usually called a process. An occam-pi PROC that runs for a bounded time and is invoked as a component in a SEQ construct (or just on its own in response to an IF condition or ALT guard) ... is usually called a procedure ... or, in OO terminology, a method.

However, this is just a convention. Technically, every syntactically complete fragment of code – even a primitive assignment or communication or timeout – is a process.

Keywords: q7


Question 46 (2006):

Submission reference: IN1011

Does the assessment require that forks are animated? Can we just have the philosphers and a security guard, because unless we make tiny weeny little hands for the philosophers and tiny weeny little forks, there doesn't seem to be any nice way to fit them into the animation :(

Answer 46:

Yes, the forks should be animated – along with reports from the security guard.

Currently, all we have talked you through (in the seminar groups) is producing a system where the college makes all its reports and a display process receives them all, outputting one (appropriate) line of text for each report. That's about enough for half marks in the assessment.

Full marks will be obtained for some minimal animation. We will be talking you through this in the seminar groups next week. Solaris executables have been placed on raptor in the directory:

    /courses/co631/answers/    (Unix path name)
    \courses\co631\answers\    (Windows path name)

The executables have the names:

    a7  a7-callanan-2002  a7-stott-2001  a7-barnes-1998  a7-griffin-2000
    a7-bodden-2003  a7-hollands-1997  a7-braun-2000  a7-sampson-2002

To execute any of these, you must open a Unix terminal window and login to raptor (e.g. by using eXceed or putty). These are solaris executables and will not run on PCs! Once opened, change to the above directory and execute, for example:

    cd /courses/co631/answers/
    ./a7-sampson-2002

The minimal standard for animation is that demonstrated by the a7 executable (where you will notice the defined limits for random thinking and eating intervals have been reduced to make the show more lively). The other examples are to challenge you – you may have to work through a few nights! If you do take up this challenge, please be original, :).

Warning: executing some of the above codes may leave your terminal window in a funny state: invisible cursor, coloured text, backspace key not working, mess on screen! Most of this can be repaired by the commands:

    clear
    reset

If that doesn't work, just open another terminal window.

Here's another challenge. Java .class files can be easily de-compiled back to reasonable source code. Try de-compiling the above back into occam-pi! [This is not a sensible challenge.]

Keywords: q7

Referrers: Question 51 (2006) , Question 51 (2006) , Question 52 (2006)


Question 45 (2006):

Submission reference: IN1010

How do we get colour for the terminal?

Answer 45:

There's an easy way ... and then there's the better way.

The easy way is to copy the (just installed) raptor file:

    \courses\co631\exercises\colours.inc

over to your exercises folder – or wherever you have your occam source code that needs it. Then, at the start of your occam source file, add the line:

    #INCLUDE "colours.inc"

This introduces a COLOUR data type (just a new name for BYTE, as it happens), a bunch of COLOUR constants (red, yellow, bold.magenta etc.) and a procedure:

    PROC set.text.colour (VAL COLOUR c, CHAN BYTE out!)

Invoking this, with the colour of your choice and screen channel, outputs the (VT100) terminal control sequence that means that subsequent text will be displayed in that colour.

A slight awkwardness is that the Transterpreter, currently, does not reset the text colour to the default (white) when it starts a new run of a program. To fix this, invoke the following on the screen channel before doing any other output there:

    set.text.colour (default, screen!)

where default is one of the COLOUR constants defined in colours.inc.

The better way is to use a library process we have pre-defined for you. Unfortunately, this is not part of the course library. Also, we have mis-named a file in the Transterpreter release and in the documentation. We will correct this – watch this space. Meanwhile, apologies.

Keywords: q7


Question 44 (2006):

Submission reference: IN1008

Can I just check that something like:

    ALT
      Guard
        Code
      ALT i = 0 FOR 5
        Code
      ALT i = 0 FOR 5
        Code

gives a 1/15 chance of selection to each element, or whether its 1/3, then 1/5 for each of the bits of code in the 2nd, if that makes sense?

Answer 44:

The above code flattens into an ALT over 11 guarded processes. Assuming all were ready, this does not give each guarded process a 1/11 chance of selection! That selection is arbitrary. One way to do it would be to choose a ready guard at random. But computing random numbers is expensive! A simpler and legal way to make the selection is to choose the first – or maybe the last. With an ALT, we can say nothing about the likelyhood of selection when more than one guard is ready. See the answer to Question 43 (2006).

Keywords: q7 , fair-alt


Question 43 (2006):

Submission reference: IN1007

I'm having some trouble with my replicated ALT. My display process contains:

    WHILE TRUE
      ALT i = 0 FOR 5
        phils[i] ? n[i]
	  SEQ
	    pause (50000) -- to be replaced by random delays in phil proc
	    out.string ("Philospher ", 0, out!)
	    out.int (i, 0, out!)
            ...  more stuff

The idea is that it'll pick an arbitrary channel from the phils array but when I run this it always seems to pick 0 for i. I tried replacing the ALT with an alternative block of code using a SEQ to ensure all the channels were producing output, which they are.

Answer 43:

I've no idea why you have a delay in response to a message from one of the philosophers?!! The delay is to model a thinking or eating period in the life of a philosopher – so that (i.e. the philosopher process) is where the delay should be invoked. The code we write in occam-pi really is process-oriented: code that relates to the behaviour of a process always is executed by that process.

[Aside: note that the same statement does not apply to object-orientation. Code that relates to the behaviour of an object might be executed by all sorts of threads of control. Unfortunately, this means that to understand/write the code for one method, we have to understand/write the code for all other methods that operate on the fields used by the orginal method and might be exectued by concurrent threads. Such logic is impossible to scale to the management of complex behaviour.]

Assuming you have no delays in your philosopher code, the behaviour you describe can be explained. At the start of each loop, every philosopher is trying to make a report - their think and eat times are zero. The ALT sees all channels with messages pending and it chooses one arbitrarily. Please note that this does not mean randomly or fairly! Always choosing channel index 0 is quite arbitrary and perfectly legal – you cannot complain.

You need to invoke delays, ideally for random amounts of time within some defined limits, in the philospher process to model its thinking and eating times. Then, there will not generally be messages pending on all report channels each time the display process starts its loop – and the ALT will cope just fine.

By the way, why does your code only receive reports from the philosophers? You may find it much easier to receive reports from all players (the philosophers, forks and security guard) in one replicated ALT (over an array of 11 report channels).

Note: sometimes we really do need to service an array of ALT guards (e.g. channel inputs) fairly – for example, when the server is under stress from the continued pushing of messages by very active clients. In this case, we cannot use a simple replicated ALT. We could try a replicated PRI ALT, but that guarantees unfairness – only channel 0 will be serviced.

However, from guaranteed unfairness, we can obtain fairness. A PRI ALT gives priority to its first guard that's ready – that's first in the listed order, not in time of readyness. Find a way to arrange that the guard serviced last time is the last in the PRI ALT order next time.

Please try to work this out – it's very simple once you see it! The technique is know as fair alting. It guarantees that no pending message has to wait more than (n - 1) cycles of a server process loop before it is taken. This gives us worst case response times in a stressed real-time system.

Keywords: q7 , fair-alt , process-orientation , object-orientation

Referrers: Question 44 (2006) , Question 51 (2006) , Question 51 (2006)


Question 38 (2006):

Submission reference: IN1002

I'm presuming BYTEs are a bit more efficient than INTs for passing small numbers around the PROCs and am therefore using them. Assuming they are better, can I change the INTs in security to BYTEs, so I don't get all confused?

Answer 38:

A BYTE communication shifts one byte – an INT communication shifts four bytes. So, yes, it is more efficient to shift only one when there is no need to shift four. But, in this application, you would need a pretty sharp sense of time to notice!

The proper reason is an engineering one: if you can do the job with less work, do so! This is a variety of Ockham's Razor: don't invent stuff that you don't need – doing so opens unnecessary scope for error. It was precisely by breaking this rule that the Arianne 5 rocket crashed in 1996, fortunately on its first test flight (though not so fortunately for the four fly-formation telescopes hitching a ride).

The security guard only has 5 numbers to report – either 0, 1, 2, 3 or 4 philosophers have been counted through to the dining room. These are all in the range of BYTE values. So, yes, let the security guard count and report in BYTEs – not INTs.

Keywords: q7


Question 37 (2006):

Submission reference: IN996

Is there an easy way to pass Strings between processes? It seems that you have to specify the length, such as [30]BYTE, but this doesn't seem a particularly amazing way to do it. Is there a way to say [however-long-it-needs-to-be]BYTE?

Answer 37:

If this question is prompted for animating the dining philosophers, relax – you don't have to pass strings around. The college components (philosphers, forks and security guard) should send coded messages to the animating process, which reacts by outputting text strings to the screen. The coded messages can be simple BYTEs (or INTs) representing states like "I'm hungry", "I'm on the table" or "I've counted in n philosophers".

However, if you have some other reason for passing around strings, use a counted array protocol as presented in the last lecture. For example:

    PROTOCOL STRING IS BYTE::[]BYTE :

This protocol (actually message structure) allows you to pass around arrays of BYTEs (e.g. strings), preceded with a (BYTE) count of how long they are. Since the largest byte value is 255, that is the longest string that can be passed with this protocol. This means that, so long as a receiving array for such a message has 255 elements, it will always be large enough – i.e. there will be no run-time array bounds overflow.

Keywords: q7 , protocol


Question 36 (2006):

Submission reference: IN988

I am probably being dense, but is there a way to get code like this to work:

    PAR
      left ! TRUE
        out ! got.left
      right ! TRUE
        out ! got.right

or:

    PAR
      SEQ
        left ! TRUE
        out ! got.left
      SEQ
        right ! TRUE
        out ! got.right

Where out is a channel to the PROC that animates everything. I currently get an error about parallel output to out if I put SEQs in, but is there a way to do it?

Answer 36:

Your first code fragment is syntactically malformed – indentation errors. Your second has a legal syntactic structure but has a semantic error – it tries to have two processes outputting in parallel to the same channel (out).

The simplest solution is not to bother reporting to the animation process when a philosopher manages to pick up an individual fork! The fork processes will be doing that – as they are picked up (or put down) – and the animation process will receive those reports. So, having the philosophers do that as well is redundant.

Only if you weren't equiping the forks with report channels would it be necessary for the philosophers to report fork movements. There are two ways to do that. Either give each philosopher two report channels: one through which it reports everything bar, say, left fork movements ... and one exclusive for reporting those latter. Or run a short-lived multiplexing process in parallel with the parallel hand movements (to pick up or put down forks), with two channels for reporting between the hand movements and the multiplexor. The multiplexor waits for just two reports, sending them to the external report channel and, then, terminates (along with the two hand movements).

I'd go for the simple solution!

Keywords: q7


Question 31 (2006):

Submission reference: IN945

This is probably an issue with my icky code but it is worth checking. KRoC produces:

    Fatal-occ21-q7.occ(162)- internal inconsistency found in routine "chan_direction_of -- not channel"
    
    *********************************************************************
    * The compiler has detected an internal inconsistency.		    *
    * Please email kroc-bugs@ukc.ac.uk with a copy of the code which    *
    * broke the compiler, as this is probably a compiler bug.	    *
    * Please include the KRoC version and any other relevant details.   *
    *********************************************************************

The offending code fragment is:

  INITIAL MOBILE []CHAN BOOL down IS MOBILE [num.phils]CHAN BOOL:

So, what's wrong? Am I doing something silly or did I find a bug in KRoC? (I highly suspect the former rather than the latter!). I've not yet tried in the Transterpreter, I guess this would be a good plan...

Answer 31:

I'd expect the Transterpreter to fail in the same way &mdash it uses the same compiler. The problem is a compiler bug, of sorts. Dynamic mobile arrays of channels are not entirely well supported, as you've discovered. The issue is that the compiler isn't allowing you to refer to the whole array 'down' (when you attempt to pass it as a parameter to another procedure).

Unfortunately I'm way too busy at the moment to fix compiler bugs (until June/July at least), so you'll have to find another way to code what you want.. Sorry :-(. But logically, what you're trying to do is sane.

PHW writes: all you're trying to do (I think?) is declare an array of channels with 'num.phils' elements. In the above, you've adapted a line from 'print.streams' that declares an array whose size is computed at run-time (from the size of the channel array argument it was passed). Your adaptation is logical but, as Fred says, the compiler does not yet support all aspects of dynamic array allocation – such as for channels.

However, if 'num.phils' is a compiler-known value (not a variable set at run-time) – e.g. it is declared somewhere towards the top of your file by:

    VAL INT n.phils IS 5:

then you can use it to declare a fixed-size array of anything, including channels, trivially – for example:

    [num.phils]CHAN BOOL down:

That should be all you need? :)

Keywords: coursework , q7

2005

Question 9 (2005):

Submission reference: IN733

Hey, just wondering if the bonus question system for the exam will be in place this year again? What I had heard about the system was that if we do all questions in the exam, we would be awarded full credit for the best 3 questions and half credit for the remaining extra question. Thanks for your time.

Answer 9:

No. Last year's rubric was deemed too complicated (although no student or staff had any problem with it!).

All rubrics for this year's papers are published here. For Co631:

    There are FOUR questions.
    Candidates should answer THREE questions,
    the ONE question from Section A and TWO from Section B.

If your answer all THREE from Section B, one of the answers will not count. Sorry -- you must follow the rubric.

Keywords: q7


Question 8 (2005):

Submission reference: IN638

With the random number generator are you supposed to create a new process to create the random number or does it go within an existing process. If this is the case do you have to have 2 random generators for thinking and eating. If the only way to get better marks for the assessment is to use this, why didn't we have it explained in lectures?...Thank you for your help

Answer 8:

The "random" thing is just a FUNCTION, so you can call it inline or wrap it up in a process; I prefer inline calls. This may not be needed for the philosophers assessment set this year, however, there's plenty of documentation on it available, it's not hard to use, and it'll produce a more convincing animation. Just because it's not required doesn't mean that you can't do/use it!

Keywords: q7


Question 6 (2005):

Submission reference: IN629

Hi, I was just wondering what kind of delays should we put in between the philosophers thinking and eating. If we set them to eat for longer than think, then you'll see the security flag up as a 5th tries to sit, however if you set them to think for longer then you'll very rarely see the security go up, if at all. What should the time delays roughly be?

Answer 6:

The delays should be random. See the other questions under the random keyword for details on how to use it.

However, you are right that the eating times should be a bit longer, mostly, than the thinking times ... to get a chance to see a hungry philosopher who is blocked by security.. Suggest making eating times random between 6 and 15 seconds, with the thinking times random between 2 and 8 seconds. If the action still seems a bit slow, reduce by a factor of 10 - experiment!

Keywords: q7 , random

2004

Question 148 (2004):

Just curious if you will/have selected any more dining philosopher solutions to add to the raptor answers collection ?

Answer 148:

Possibly -- I've already put one into the KRoC/Linux distribution's set of dining philosophers, but this can't go on raptor because it uses some of the occam-pi extensions (not supported by the version of KRoC installed on raptor). We might put some more in, and put on raptor (if compatible).

Keywords: q7 , model-answers


Question 122 (2004):

Hi, I've completed the q7 coursework but I would like to ask a question before I submit it. I found no need for the "PROC secure.college", so I removed it and did all the necessary wiring in "PROC q7". The animation still works and I feel I can understand my code better this way. Will I be marked down for the removal of "secure.college" ?

Answer 122:

Yes, you will lose marks. There is a reason for having "secure.college" - namely structure! Discarding it leaves its innards and the "display" at the same level of network ... which is (a) more complicated and (b) illogical. Please tidy them back into a "secure.college" wrapping.

Keywords: q7


Question 121 (2004):

Continued from Question 120 (2004)... I'm actually working with a 2D array, although I don't think that makes any difference ? I'm not getting an error, it's a little strange but it appears to remove the byte, for example with:

    log[0] := "Philxxxis eating "
    log[0][5] := (BYTE n)

after this operation, "log[0]" seems to contain "Philxxis eating ". Any ideas ? I'm feeling slightly baffled.

Answer 121:

The reason this is probably happening is because "BYTE n" is not a printable character. Casting an INT to a BYTE does not produce the character representation of the number in base-10 (decimal) -- it produces the ASCII character with the value of the integer. If you want to print out a number as its (decimal) character representation, use "out.int".

Keywords: q7


Question 120 (2004):

In occam, if I've got a BYTE array, I would have thought I could do something like this: (where "i" is an INT)

    array[5] := BYTE i

but it doesn't appear to work, can you explain why that is, when something such as this works perfectly fine: (where "b" is a BYTE).

    array[5] := b

Answer 120:

That should work fine, and does for me.. What error (exactly) are you getting ? Something else must be wrong..

Keywords: q7 , arrays

Referrers: Question 121 (2004)


Question 119 (2004):

Oh dear oh dear - q7-bodden-2003: it just crashed on me after running for a while! Shocking.

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

Aren't these supposed to be 'model' answers? ^_^

Answer 119:

Humm ... I guess you mean the a7-bodden-2003 program ... there isn't a q7-bodden-2003 one?!! [Actually, it's simple naming typos like these that cause masses of software crashes, :(]

But, seriously, a7 is the model demo executable. All others are to give you ideas/challenges. We haven't verified them completely. Thanks for telling us that that one breaks. We will fix ...

Keywords: q7


Question 118 (2004):

Do you think anyone would be offended if someone were to name their philosophers after occam seminar leaders ;)

Answer 118:

No ...

Keywords: q7


Question 117 (2004):

Hi there, can you give some clues of how to get the forks working in Q7. Everything I am trying isn't working :-(

Answer 117:

The forks already work by default -- adding the reports shouldn't break them! The best idea would be to mail your seminar leader with a copy of the code, who can then advise on what the problem is.

Keywords: q7


Question 116 (2004):

Is A7 the minimum you expect from us for Q7 ?

Answer 116:

It's minimal in the sense that if you implement something that produces similar output you can get 100%. But that's a generous estimate; some marks are inevitably lost for untidy coding, errors, etc.

Keywords: q7


Question 115 (2004):

When I try to run my q7 answer on my Linux box (Mandrake 10.1) I get this error:

    KRoC: unable to find clock file (.kroc_clock or /etc/kroc_clock)

What does it mean and what can i do to fix it ?

Answer 115:

It's because you're missing the KRoC clock file. When you installed the software it prints out a message saying that you must copy "~/.kroc_clock" to the current-directory or to "/etc/". This file just contains your CPU speed in MHz (as read from "/proc/cpuinfo"). Newer versions of KRoC/Linux (1.3.4-pre4 and above I think) will automatically read the speed out of "/proc/cpuinfo" if a clock file isn't found.

Keywords: q7 , linux


Question 114 (2004):

How do we submit our dining philosopher's assignment?

Answer 114:

Copying from the newsgroup announcement ...

Your assessment, "A4 DINING PHILOSOPHERS ANIMATION", is due on Monday in week 18 - i.e. Monday, 14th. February, 2005.

This time, we want to compile and run your programs! Submission directories are open at:

  \\raptor\files\proj\co516\q7\        (from Windows)

or:

  /usr/local/proj/co516/q7/            (from Unix/raptor)

Please copy your source code (.occ) file(s) there. Please do *NOT* copy executables. You only have access to <your-login-name> directory.

If your solution follows the standard model (i.e. an array of channels connecting the college process and the display process, with the display also connected to the screen channel), you do *NOT* need to include a network diagram.

If your solution has a non-standard network, please include a network diagram with your submission. This can be as a .pdf, .ps, .ppt or .doc file. For anything else, you must submit hard copy to CAS reception together with a cover sheet. A neat hand-drawn diagram is very acceptable through that route.

The submission directories will close at midnight between Monday/Tuesday - i.e. at 00:00 on Tuesday, 15th. February.

Keywords: q7


Question 113 (2004):

Hello. I saw your answer to Question 109 (2003) about the colours in text and was wondering where and how to find out the codes for other colours. Thanks.

Answer 113:

Well, the answer to the question you referenced says to do a quick Google search. I just did and it came up with this link which, when combined with Question 109 (2003), tells all, :).

Keywords: q7


Question 112 (2004):

Why is this bit of code gvining the error: Parallel outputs on channel out, when the channels down and up are used in security as well as philosopher?

   [Code snipped]

Answer 112:

As said many times before, we can't debug specific code on these pages!

However, the compiler is generating a correct error message - it usually does. Your network has mutliple processes writing to the same out channels - the up and down channels are irrelevant here.. When you've fixed that, you might want to put those out channels in the parameter list for secure.college - having them as local channels mean they don't connect to anything in the world outside the college ... such as a display process ...

Keywords: q7


Question 111 (2004):

Is it possible we can actually see the implementation of the PROCs, like: "erase.screen()", "erase.bol()" and others in the utils file ?

Answer 111:

Yes, just look at the source code! See Question 63 (2003) for an indication of where it is.

Keywords: q7 , course-library


Question 110 (2004):

Is this the correct piece of code for waiting a random time ?

    SEQ          
      seed := seed + id
      i, seed := random(num, seed)
      tim ? t
      tim ? AFTER t PLUS i

Answer 110:

More or less, yes. Make sure you initialise "seed" appropriately though -- the code above initialises it based on itself (if undefined, it'll stay undefined). As covered in the seminars, a quick way to get an initial seed value is:

    tim ? seed
    seed := (seed >> 2) + 1   -- maybe also add in the `id'

Remember also that your seed should be explicitly initialised like this just once -- before loop entry. Within the loop, cycling through the philosopher's life, the seed value gets updated as you use the random function. The sequence of seed values takes you through the "random" numbers. If you re-initialise the seed every time round the loop, the computed randomness will be lost.

Keywords: q7 , timers


Question 109 (2004):

How many more channels need to be added to the PROC header of the philosopher? When I add an output channel to my "fork", "philosopher" and "security" PROCs, I get an error in the "secure.college" PROC stating parallel outputs on one channel. How do I get around this?

Answer 109:

Form the code from the diagram of it -- you'll see that there is only one additional (report) channel coming out of a philosopher, so that's all that should be added to its header. The error relating to parallel output is in "secure.college", so that is where the error lies -- not in "philosopher", etc. A key rule is you can't do parallel outputs to the same channel. So, we need an array of channels, one for each of the reporting processes inside "secure.college". The "display" process takes the other (reading) end of that array of channels. How to do this has been covered fairly extensively in the seminars. If you're already using an array of channels, check the indices you're using -- one or more must be wrong if the compiler is giving you this error (you can expand the replicators by hand to see where the error lies).

Keywords: q7


Question 108 (2004):

I'm thinking of changing my protocol from:

    PROTOCOL REPORT
      CASE
        thinking
        hungry
        ...
    :

to:

    PROTOCOL REPORT
      CASE
        thinking; INT
        hungry: INT
        ...
    :

to tell me which philisopher is hungry, thinking, etc. Is this a wise move or is there another way I can find this out in the "display" process ? Currently I'm ALTing over the channels to see if they're thinking, hungry, etc.

Currently if a philisopher is thinking it prints (philosopher is thinking) with no knowledge of who is thinking.

Answer 108:

Yes, this probably is a wise move. The only other way you can get that information is by having the "display" process knowledgeable about its wiring. I.e., in the array of "REPORT" channels, which channel is connected to which philosopher, etc. This is not entirely desirable, however, since re-wiring such a network would break the "display" process.

Keywords: q7 , protocol


Question 107 (2004):

This is used for the animation:

    SEQ
      clear.states (4 + (4 * n), out)
      ...

but when I try to use "clear.states" I get an error! help.

Answer 107:

Saying what error you get might be useful.. But "clear.states" must be something you've defined yourself -- it's not provided by any library. The errors generated by the compiler are generally meaningful and useful, and should be telling you what the problem is.

Keywords: q7


Question 106 (2004):

Could you explain "SHARED" channels again and maybe give an example ? From the class they seem like a cleaver idea but now when it comes to coding them I am a little lost.

Answer 106:

[Note: the first part of this answer is now obsolete! The SEMAPHORE data type is no longer supported by the multicore run-time systems for occam-pi. The second part of this answer (using SHARED channel) is the correct way to do things now.]

There are two ways to do shared-channels in occam, and which one you choose will depend on whether you're coding on Linux or Solaris.

KRoC/Linux has built-in support for shared channels, called "anonymous channel types" in the form most useful for Q7. You can find a fairly terse example of these here.

Shared channels on the KRoC installed on raptor must be done manually -- by turning off compiler usage-checks and using "SEMAPHORE"s to provide mutual exclusion.

For comparison and reference, below are two equivalent versions of a simple test program that use shared channels:

    #INCLUDE "semaphore.inc"            -- NOTE: this version is no longer valid.
    #USE "course.module"

    PROC hello (SEMAPHORE sem, CHAN BYTE out!, VAL INT id)
      SEQ
        claim.semaphore (sem)
        --{{{  output stuff
        out.string ("hello world from ", 0, out!)
        out.int (id, 0, out!)
        out.string ("*n", 0, out!)
        --}}}  
        release.semaphore (sem)
    :

    PROC main (CHAN BYTE kyb, scr!, err!)
      #PRAGMA SHARED scr
      SEMAPHORE sem:
      #PRAGMA SHARED sem
      SEQ
        initialise.semaphore (sem, 1)
        PAR i = 0 FOR 10
          hello (sem, scr!, i)
    :

and (if using KRoC):

    #USE "course.module"

    PROC hello (SHARED CHAN BYTE out!, VAL INT id)
      CLAIM out!
        SEQ
          --{{{  output stuff
          out.string ("hello world from ", 0, out!)
          out.int (id, 0, out!)
          out.string ("*n", 0, out!)
          --}}}  
    :

    PROC main (SHARED CHAN BYTE scr!)
      PAR i = 0 FOR 10
        hello (scr!, i)
    :

but (if using the Transterpreter – see Question 22 (2008)):

    #USE "course.lib"

    PROC hello (SHARED CHAN BYTE out!, VAL INT id)
      CLAIM out!
        SEQ
          --{{{  output stuff
          out.string ("hello world from ", 0, out!)
          out.int (id, 0, out!)
          out.string ("*n", 0, out!)
          --}}}  
    :

    PROC main (CHAN BYTE key?, scr!, err!)

      SHARED ! CHAN BYTE screen:             -- output end shared

      PAR

        PAR i = 0 FOR 10
          hello (screen!, i)

	WHILE TRUE                           -- byte "id" process
	  BYTE ch:
	  SEQ
	    screen ? ch
	    scr ! ch

    :

Keywords: q7 , shared-channel


Question 104 (2004):

I have a quick question relating to my 'animation' - could you give any tips/ideas for nice(r) way of making the philosophers move about the screen without hard coding in the locations of every movement?

In my more 'advanced' animation (which has been a challenge to say the least) I have had a lot of hassle using a hard coded method. The code just to move a philosopher to the table (and it's currently not very smooth) is around 300 lines. Ouch.

I am sure there is a better way of doing things but I have racked my brains and I can't think of anything :(. The only other idea was to create a "large" VAL [][5][2]BYTE array that stored all the locations, and for each movement the required value is pulled out the array. That doesn't seem much nicer though; occam doesn't seem to allow you to span this sort of thing over multiple lines either.

Any sort of help would be greatly appreciated, however small!

Answer 104:

If ever you find yourself writing long sequences of repetitive code, where the differences are primarily in number values, you are doing something wrong, ugly and inefficient! So, your 300 lines of code is not a good idea.

Your 'better way' is much better, although it can be improved (see towards the end of this answer). Your VAL [][5][2]BYTE is, presumably, a 2-dimensional array of coordinates (i.e. [2]BYTEs), with the [5] index being for the philosophers and the unsized outermost dimension (i.e. []) being for the number of coordinates (i.e. the length of the path). That might make slightly more sense (and convenience for programming) with the two outer dimensions swapped around -- i.e. VAL [5][][2]BYTE.

occam does allow long lines to be broken across multiple lines ... but maybe I never told you! You can break a long line after commas, operators and the keyword IS. For example, the very long one-line declaration:

  VAL [n.phils][][2]BYTE path IS [[[13, 12], [14, 12], [14, 13], [14, 14], [14, 15]], [[23, 12], [24, 12], [24, 13], [24, 14], [24, 15]], [[33, 22], [34, 22], [34, 23], [34, 24], [34, 25]], [[83, 82], [84, 82], [84, 83], [84, 84], [84, 85]], [[93, 92], [94, 92], [94, 93], [94, 94], [94, 95]]]:

can be much more readibly laid out:

  VAL [n.phils][][2]BYTE path IS
    [[[13, 12], [14, 12], [14, 13], [14, 14], [14, 15]],
     [[23, 12], [24, 12], [24, 13], [24, 14], [24, 15]],
     [[33, 22], [34, 22], [34, 23], [34, 24], [34, 25]],
     [[83, 82], [84, 82], [84, 83], [84, 84], [84, 85]],
     [[93, 92], [94, 92], [94, 93], [94, 94], [94, 95]]]:

The rule about indentation for continuation lines is that any indentation at least as great as the initial line is allowed. So, the following, rather stupid, layout is also possible:

  VAL [n.phils][][2]BYTE path IS
    [[[13, 12], [14, 12], [14, 13], [14, 14], [14, 15]],
           [[23, 12], [24, 12], [24, 13], [24, 14], [24, 15]],
  [[33, 22], [34, 22], [34, 23], [34, 24], [34, 25]],
   [[83, 82], [84, 82], [84, 83], [84, 84], [84, 85]],
         [[93, 92], [94, 92], [94, 93], [94, 94], [94, 95]]]:

but we wouldn't, of course, ever do that! Another use of breaking lines after commas we have seen lots of times -- in PROC headers with long parameter lists:

  PROC thing (CHAN OF INT in0, in1,
	      CHAN OF BYTE keyboard, screen, error,
	      VAL INT id, interval,
	      [][]REAL64 data)

instead of:

  PROC thing (CHAN OF INT in0, in1, CHAN OF BYTE keyboard, screen, error, VAL INT id, interval, [][]REAL64 data)

Breaking lines after operators helps keep large expressions neat -- for example:

    first := (first - second) + ( ((-first) + (third - second)) * (rotational.torque - (ratio/2)) )

could be written:

    first := (first - second) +
	       ( ((-first) + (third - second)) *
		 (rotational.torque - (ratio/2)) )

which might help a little.

Getting back to improving your path description for a wandering philosopher ... rather than declare a table of absolute coordinates for each path position, consider a table of relative movements. For example:

  VAL [n.phils][][2]BYTE path IS
    [[[left, 3], [up, 5], [right, 2], [up, 4], [left, 1], [down, 2]],
     [[down, 8], [up, 3], [left, 6], [down, 1], [left, 6], [down, 3]],
     [[right, 3], [down, 2], [right, 8], [down, 9], [right, 1], [down, 5]],
     [[up, 5], [left, 5], [down, 2], [up, 2], [down, 1], [up, 3]],
     [[up, 9], [right, 9], [up, 2], [left, 2], [up, 3], [left, 6]]]:

where your movement code interprets [left, 3] as "move left 3 places" etc. Predeclared, of course, would need to be something like:

  VAL BYTE left IS 0:
  VAL BYTE right IS 1:
  VAL BYTE up IS 2:
  VAL BYTE down IS 3:

Elsewhere would be needed a table of absolute start coordinates for each path movement.

That just leaves the problem that all the above path lengths have to be the same length? With the modern occam-pi language, that's not a problem ... we can use dynamically sized mobile arrays. For classical occam, you could pad out short paths with some dummy movement elements - e.g. STAY where:

  VAL BYTE stay IS 255:

  VAL [2]BYTE STAY IS [stay, 0]:

  VAL [n.phils][][2]BYTE path IS
    [[[left, 3], [up, 5], [right, 2], [up, 4], STAY, STAY],
     [[down, 8], [up, 3], [left, 6], [down, 1], [left, 6], STAY],
     [[right, 3], [down, 2], [right, 8], [down, 9], [right, 1], [down, 5]],
     [[up, 5], [left, 5], STAY, STAY, STAY, STAY],
     [[up, 9], [right, 9], [up, 2], [left, 2], [up, 3], STAY]]:

Keywords: q7 , animation , long-lines

Referrers: Question 43 (2009) , Question 30 (2008)


Question 103 (2004):

How do I output the value of "n.sat.down" to the screen ? Is the only way to add an "out" channel the PROC header and do an "out.int" on it ?

Answer 103:

If "n.sat.down" is a tag in a variant protocol, it doesn't have any meaningful value. Some meaningful data might be communicated as part of the protocol, however. You mention adding an "out" channel, but to what PROC in particular ?

To avoid complication, the correct place to handle the output of this information is in your "display" process. Wiring it up to the "security" process (by default the only process that knows how many philosophers are sat down) should be fairly straight-forward.

Keywords: q7 , output


Question 102 (2004):

Is it possible to specify more than one condition in an "IF" process ? For example:

    IF
      x = 0 AND y = 0
        -- do something

If so which operators should be used ? When I compile something similar to the above I get an error saying:

    Expected new line, found AND

Answer 102:

This error occurs because you need explicit bracketing (occam has no operator precedence), even though the alternatives don't make much sense in this case. The correct way to write that would be:

    IF
      (x = 0) AND (y = 0)
        -- do something

Keywords: q7 , operators


Question 101 (2004):

Do we need to use occam that is going to work on raptor or can we make use of the additions in the KRoC/Linux version. For example I'm considering using the STEP stride part for the replicator.

Next when using replicators, why can't I pass "i" into the "cursor.x.y()" PROC in this code ?

    PAR i = 8 FOR 5 STEP 2
      SEQ
        cursor.x.y (23, i, out)
        -- print stuff

Where "i" is the line number. The error is a type mismatch for parameter 2 in "cursor.x.y()". Surely "i" is an integer and should be accepted ?

Any help appreciated...

Answer 101:

For KRoC/Linux extensions (rather, occam-pi extensions), yes, using those is fine. We'll most likely be testing your code on such a machine.

The reason you can't pass "i" as a parameter is because "cursor.x.y" takes "VAL BYTE" parameters (not "VAL INT"). The solution for such things is to cast the parameter to the appropriate type:

    cursor.x.y (23, BYTE i, out)

Given the code you've got above, it should generate another error also (related to parallel usage), but that should be slightly more obvious.

Keywords: q7 , cast


Question 99 (2004):

Why in "PROC philsopher (...)", do you have:

    PAR                -- pick up
      left ! TRUE      -- forks
      right ! TRUE

    ...  eat

    PAR                -- put down
      left ! TRUE      -- forks
      right ! TRUE

i.e. why is the code the same for pick up and putting down the forks ?

Answer 99:

The reason is simply that it requires less channels. Extra channels could be added for the putting-fork-down events, but it's better if we can re-use the existing channels (less coding and less plumbing on the network diagram). The same reasoning applies to the fork process -- adding extra channels is possible, but unnecessary.

The direction of communication along the left and right channels is important to the fork process. That has to choose (i.e. ALT) between competing signals from its adjacent philosopher processes, who might be trying to pick it up. That signal is represented by a channel communication. We can only ALT between input communications, so the forks must input and the philosophers must output. This is for picking up the forks.

For putting down the forks, neither side needs to ALT ... so the direction of the communication, signalling this event, doesn't matter. So, the fork could output to the philosopher who picked it up (and be blocked until that philosopher did a corresponding input to indicate that it was putting down the fork). But, then, we would need another channel (a putting-down-channel) between each philosopher and fork - since channels may be used in one direction only and we are forced to use the existing ones in the other direction. So, the simplest thing is to reuse the existing channels and get the fork to input from it (and be blocked until the philospher holding it does an output to indicate that it was putting down the fork) ... which is what happens.

Note that we do use different channels between each philosopher and the security guard to represent the let-me-in-to-the-dining-room and let-me-out signals. The security has to ALT between all of these, so the direction of communication has to be from the philosophers to security. The security has to ALT both for the let-me-in and let-me-out signals, unlike the fork (which only has to ALT for the pick-up signals). But the security has also to refuse further let-me-in signals -- if four are already in -- whilst allowing let-me-outs! Doing that trick with only one channel used for both let-me-in and let-me-out signals is hard. So, we used separate channels.

Keywords: q7


Question 96 (2004):

Do we put the "VAL INT id" call inside the "PROC" header for philosopher and fork, or is this done in the main body of the "PROC" ? I think it is the former, but I'm not sure how to replicate this in "secure.college".

Answer 96:

Be careful of your terminology -- "VAL INT id" would either be a parameter or abbreviation (that latter which you're unlikely to be using). It's not a "call" of any kind.

You are correct in thinking it should be in the PROC header for the philosopher, but what the PROC gets is a value (the "VAL" bit), not a variable. The replication in "secure.college" is already done for you -- you just need to "plug-in" the desired value (that should be fairly obvious if you look around, or compare the code with the network diagram for it). Also, looking at previous questions relating to q7 (particularly for previous years) will tell you the answer.

Keywords: q7


Question 95 (2004):

There seems to be some conflicting deadlines for Q7 ? On the Student Portal it says:

CO516
 Parallel and Imperative Programming
 A4 DINING PHILOSOPHERS ANIMATION
 Mon, Wk 18 
 Tue, Wk 3 
 phw
 Mon, Wk 21 
 Reception

on the co516 webpage it says:

ASSESS 4 A4 DINING PHILOSOPHERS ANIMATION 60 32 3 Tuesday 17 Thursday

and my seminar leader says the 14th Feb is the deadline. Which of the above is the correct deadline?

Answer 95:

Monday of week 18 (14th February) is the actual deadline, as we have been telling you in the seminar groups. So it's the webpage that's wrong. The data that appears under "assessments", etc. is not current -- we're not allowed to pull data from the live student database so stuff there will always lag behind the real student database.

Keywords: q7


Question 89 (2004):

Have we covered enough material to start the dining philosophers this holidays ?

Also are there any useful areas we can start to look at for revision (in terms of website with practice questions on what we've covered so far?)

Answer 89:

The dining philosophers have been covered in the lecture, so yes, you could in theory make a start on this. But we'll be looking at this in more detail (e.g. ways of doing animations, etc.) in the seminars next year.

For revision material: the course notes (including the various papers on occam); Fred's occam tutorial; and past exam questions. But these are all obvious..! You should be able to decide for yourself whether something in a (past exam) question has been covered or not. Your own lecture notes may also be useful to this end.

Keywords: q7

2003

Question 117 (2003):

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 116 (2003):

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:
    SEQ
      forkStat[0] ? x
      IF
        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 115 (2003):

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
      PAR
        philosopher (...)
        for (...)

Keywords: q7


Question 114 (2003):

Hi,

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 113 (2003):

Hi,

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:

    SEQ
      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 112 (2003):

Hi,

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

    PAR
      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.:

    PAR
      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.

Thanks.

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!)
      PAR
        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.:

    PAR
      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 106 (2003):

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 98 (2003):

How do we submit q7 ? Do we just hand in the hard copy at the octagon or do we need to submit this electonically as well?

Answer 98:

The submission of the code will be electronic (so we can test/run your programs). You'll also need to submit a network diagram (on paper) to the CAS office. Keep an eye on the CS2 newsgroup for submission details (will be posted nearer the deadline).

Added later: submission directories have now been set up for you on raptor:

  /usr/local/proj/co516/q7-2004/your-login-name/      (Unix view)
  \\raptor\files\proj\co516\q7-2004\your-login-name\  (Windows view)
Please copy only your source code file(s) into there - usually this will just be one file called q7.occ. You can do this as often as you like up till the deadline - midnight, Thursday, 12th. February (that's the midnight between Thursday and Friday).

You must also submit a paper copy of all relevant network diagrams for your solution. These must correspond to your code submitted electronically, with all channels labelled with the names used in your code. Don't forget to indicate directions of channel flow. This copy may be machine produced or neatly drawn by hand. This part of the submission must be to the CAS office, with a cover sheet (copies of which will be in the Co516 pigeon hole, near CAS Reception), BEFORE they close at 4pm on that Thursday.

Keywords: q7


Question 97 (2003):

I have an input channel into `secure.college()' of type INT which will contain the ID for each philosopher and fork. This channel will be connected to both the philospher and fork PROCs. How do I make sure that I get a number that is one greater than the previous down the channel so that each philosopher has a unique ID?

Answer 97:

If you try and write code as you suggest above, the compiler will simply reject it (on a parallel (mis)usage error). Assigning IDs this way is hard. One question you should ask yourself is: ``do I really need to convey this information to the philosophers/forks using a channel communication ?''. The answer to that is: no. A `VAL INT id' parameter (for philosophers and forks) would be much simpler, and much clearer.

Keywords: q7


Question 96 (2003):

I'm trying to do a fair-ALT, but there are 11 channels to ALT over and thats a lot of of code! I was wondering is there a way of looping around FOR statements? What I mean is if the first time you write, say,

    ALT i = 0 FOR 5

is there anyway so that the second time I can write

    ALT i = 1 FOR 5

but have it so the 5th iteration loops back to channel 0 (i.e. the one I started on the first time). Sorry if thats unclear.

Answer 96:

I'm not sure what you're asking here -- at a guess you're confused as to the operation of a replicated-ALT. One key idea is that it is a replicator, not a loop as such. Writing:

    ALT i = 0 FOR 5
      in[i] ? x
        P(x)

is equivalent to:

    ALT
      in[0] ? x
        P(x)
      in[1] ? x
        P(x)
      in[2] ? x
        P(x)
      in[3] ? x
        P(x)
      in[4] ? x
        P(x)

For more information, look in the course notes that describe the ALT, around slide 5-29. The code for a fair-ALT is also given explicitly on slide 10-23, as you have been told many times! Also check out other related anonymous questions, particularly those on alternation and the fair-alt.

Keywords: fair-alt , q7


Question 93 (2003):

I seem to have some problems with the security. If 4 philosophers are sitting, it reports that 3 philosophers are sitting until another philosopher moves: at that point it says that 4 philosophers are sitting. This is my code for the philosopher and security:

    [snip code]

Answer 93:

Usual things about not posting huge chunks of code to the anonymous Q+A page. This sort of question should be directed to your seminar leader.

However; the code you posted looks fine. Check that your `display' process flushes the output when that information is updated. The problem you describe sounds like a classic symptom of this.

Keywords: q7


Question 92 (2003):

Are there any example source files of animation; I attended the seminar, but am having problems with even starting to animate.

Answer 92:

There were four seminars you should have attended ...

You could look at `test_utils.occ' in:

    /usr/local/courses/co516/examples

on Raptor. Or `examples/sort_pump.occ', but that uses `goto.x.y', which is now deprecated, rather than `cursor.x.y' (the two are essentially similar, however).

Essentially, text-animation is a repeating process of: move cursor, then output something. This can be seen most obviously in the `a7' model answer.

Source code for other animations can be found on Fred's occam page. These range from trivial to rather complex.

Keywords: animation , q7


Question 91 (2003):

I'm confused on how to get the forks to move correctly. Is it a better idea to have to separate tags for left and right forks (``left.fork'', ``right.fork'') or to just have one (e.g. ``fork; INT'') ?

Answer 91:

You need to mention what the `INT' is for, really. If it's the `id' of a fork, then that's one bit of information, but left/right is separate. Fork `i', for example, can be picked up or put down, by the philosopher on the left or right. The question is: do you need all this information from the fork, or just some of it, to do the animation ? -- watching the `a7' model answer should tell you this.

Keywords: q7


Question 88 (2003):

I have some mystery regarding Q7 I'd like to clear up. As I understand it the college must communicate its status to the display process via a number of channels. I think the only thing the display process needs to know is the status of each philosopher; the status of security and the forks can be deduced if we know what the philosophers are doing.

As it stands the college is self contained and there is no obvious way to report, at any given time, its status to another process. One solution I can see is to replicate all communications between the processes in college, and route them to the display process. The display process would maintain its own picture of the college, which it updates according to the inputs on its channels. This seems rather complicated.

Alternately the display process could again recieve a copy of all internal college communications, but conforming to a protocol such that it can update its picture of the college without other information about its status. For example, when a philosopher wishes to sit down, instead of outputting a boolean he outputs a specific message the display process knows to mean "waiting to sit down" and can update its picture accordingly. This is assuming that the animation is not drawn frame at a time, but continuously updated as information comes in.

In these cases what does display need to communicate with in order to get a complete picture ? Security can tell it who is wanting to sit down and stand up, but it also needs to know the fork status. Presumably this will be the job of either forks or philosopher.

I have trawled the anonymous questions of old, none of the answers to which have baffled me, but I still cannot get this fundamental.

Answer 88:

All the questions you have asked have been discussed in your seminar groups for the last 4 weeks. These Q&A pages are in no way a substitute for attending those seminars. Your question suggests ideas that are either illegal (with respect to occam semantics) or far too complex. Simple solutions have been presented in the seminars.

Having said this, I will attempt to answer your questions. However, those who know how to do this problem should skip these answers, as correcting the confusion in your questions may confuse others unnecessarily.

In response to your first paragraph, yes, the state of the forks can be deduced from the philosopher, but it's easier to have the forks report their state. It also makes more sense; the state of a fork should be reported by the fork, not by something else.

You are sort of correct in your second paragraph, although I'm not sure what you mean by `replicate all communications'. Thankfully, setting up this extra `wiring' is not complicated in occam. However, the `display' process does not need to maintain the `state' of the college (see the next paragraph). The extra wiring can be handled using an array of channels; the `display' process gets the inputting ends as a `bundle' (array), whilst the outputting ends are distributed amongst the other processes. This will require some modifications to the `secure.college' process.

The third paragraph is essentially what we're expecting you to do for this assignment. The `philosopher', `fork' and `security' processes report their actions to the display as they happen. The display process just inputs these messages and draws on the screen accordingly. The animation should indeed be updated on-the-fly; it should not be done frame-by-frame. The only disadvantage is that the display cannot be completely redrawn (i.e. if it got corrupted, somehow). This isn't a problem for this assignment, however.

The various messages are best handled using a tagged protocol. The previous assignment, q6.occ, used a tagged protocol. The various `messages' have been discussed in the seminar groups. The q7.occ file gives some indication of what is required:

    Your task is to animate this demonstration.  Links will need to
    be made from the college to its external environment, through
    which the philsophers (and, maybe, the forks and the security guard)
    report their state.  These links are gathered by a fair-ALTing server
    that drives a screen display in response to incoming information
    from the college.  Thinking and eating by the philosphers should
    be modelled by random (but finite!) delays.  The animated display
    should reflect the round table in the dining room ...

Running the example solutions (on raptor, see Question 80 (2003)) should give you an indication of what is required -- i.e. what is being displayed (and therefore reported) there ? (`a7' is the example minimum-but-full-marks solution; the other example solutions are more animated).

Reporting by each process should be restricted to its own `state'. I.e., the security process should not report that philosophers are trying to stand up or sit down. This is actually very hard. The only state the security process maintains is how many philosophers are actually sat down -- it should report this. When a philosopher stands up or sits down, that should be reported by the philosopher -- not anything else. It is both more logical and simpler to have things this way, since it keeps the logic of each process `intact'. E.g. I might take your philosopher, fork, security and display processes, completely re-wire the nextwork (within reason), and still expect it to work. Having the correct functioning of processes depend on their external wiring is not really a good idea.. (such processes must conform to the protocol that they conceputally agreed on, however).

I hope this clears things up a bit. If you still have queries, or want some points explained in more detail, I'd suggest emailing or visiting your seminar-leader or other member of the course team (we all have a desk somewhere on campus).

Keywords: q7 , animation


Question 87 (2003):

Hi, what datatype does `cursor.x.y' take as im getting errors about wrong parameters.

Answer 87:

The `x' and `y' parameters are BYTEs. The PROC header for `cursor.x.y' is:

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

See the answer to Question 7 (2000) for information on how to do a type-cast in occam.

Keywords: q7


Question 83 (2003):

I am stuck trying to do the implementation of philosopher, I know that we should try and use a random time, but at the moment I am just trying to implement it with a static time, say 5 secs.

    [snip code]

Thats what ive done so far, and dont really know how to do the think and hungry stuff.

Thanks for any help

Answer 83:

We've mentioned this before, but posting large chunks of code to the anon Q+A page and simply asking what's wrong isn't particularly useful -- the anon Q+A is a group forum, not an individual forum. You question would have been better directed to your seminar leader.

The code you pasted is largely the default `philosopher' code, with some minor additions.

If you want to know about the `random' function or timeouts, see the keyword index entries for timers and random. Reading through the questions and answers for past questions (particularly relating to q7) should hopefully answer any questions you might have. Alternatively, talk to your seminar leader (preferably during the seminar).

Keywords: q7


Question 80 (2003):

Can we still get full marks on q7 if we just do a basic line by line 'animation' of what is going on ?

Answer 80:

If you have just a scrolling output of events, the answer is no. The minimum solution (that can get full marks) is a table-driven animation, shown by the `a7' example answer. This can be found on raptor in the `/usr/local/courses/co516/answers/' directory.

Keywords: q7

Referrers: Question 88 (2003)


Question 79 (2003):

Having problems with q7. In our seminar we were told to use:

    i, seed := random (n, seed)

to create a random number. Can you explain what each of the elements are, also can you give a basic example.

This part of the Philosopher proc is going to be a base for all 5 philosophers, but there is the problem of each having the same random number for each one. Do we need to have a different value of `n' and `seed' each time the PROC is run? Or is this dealt with by the random function ?

Answer 79:

The `seed' is there to initialise the random number generator. More specifically, it is the internal state of the `random' function -- functions cannot retain their own state.

Before you call `random' for the first time, you need to initialise `seed' to a number between 1, and the maximum positive integer minus one. When you call `random' for a second time, use the new `seed' returned by the first call, and so on.

Yes, you need a different starting seed for each philosopher (hint: each philosopher has a different `id').

`n' is the range of the random number generated. i.e. `random' will return a random value between 0 and (n-1); in your example, assigned to `i'.

Keywords: random , q7

Referrers: Question 33 (2007)


Question 78 (2003):

I'm quite confused on how I can assign each philosopher an identity. I've modified the header of the PROC philosopher in the following way:

    PROC philosopher(CHAN OF INT id, CHAN OF BOOL left, right,down, up, CHAN OF MESSAGE report)

This means that the display PROC has 16 input channels. I'm not sure this is the right way of doing it.

Answer 78:

Assigning IDs to the philosophers is better done by simply using a ``VAL INT'', passed to each philosopher from the PAR replicator that sets the network up.

Communicating the ID to each philosopher (using the `id' channel you added) is certainly possible, but definitely not the simplest way.

Keywords: par , q7


Question 76 (2003):

Hi, I'm just experimenting with my animation for q7 and I've come across an annoying problem with protocols in occam. My problem is that each channel seems to have a buffer. This creates a problem in protocol channels because there is no FLUSH like with the screen output. This means I have forks multiplying all over the place and philosiphers jumping around in mad bursts, despite huge delays tha are supposed to be in their movement. Is there any way of creating the effect of FLUSH on a protocol channel?

Answer 76:

Channels have no buffers - no matter what their protocol. So you have to explain/analyse your problem a bit more. Once a channel output has completed, the other side has definitely taken it. Your channel output does not complete because the channel has buffered your message in some way.

If what you want is for the outputting process *not* to continue until the inputting process has completed some response to its input, you need to program that - e.g.:

    PROTOCOL THING
      CASE
        data; ...                  -- the message types
	other; ...                 -- other message types
	...
        complete                   -- only accepted once response is complete

Then the sending process:

    SEQ
      ...  stuff
      c ! data; ...
      c ! complete                 -- wait for response (e.g. animation) to complete
      ...  more stuff

and the receiving process:

    c ? CASE
      data; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE
	    complete               -- let sender know all is done
	      SKIP
      other; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE
	    complete               -- let sender know all is done
	      SKIP

Note: here is a little bit more of occam! If a CASE input only deals with one case (as in the above), it can be shortened to a one-liner:

    c ? CASE
      data; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE complete        -- let sender know all is done
	  SKIP
      other; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE complete        -- let sender know all is done
	  SKIP

If the response to that one case is SKIP, that response can, of course, be now omitted:

    c ? CASE
      data; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE complete        -- let sender know all is done
      something.else; ...
        SEQ
          ...  response (e.g. animation)
          c ? CASE complete        -- let sender know all is done

Hope that helps! [Note: you only need to engage in such trickery if you have more than one process doing animation. If you have just the one and it does some animation in response to a received message, then that animation will complete before it processes the next message and does the next animation. This is all that's needed to do the minimum form of animation required for full marks - as shown by the executable model answer (answers/a7). However, to get parallel animation - see some of the other example answers - you will naturally need parallel processes and tricks as outlined above.]

Keywords: q7

Referrers: Question 106 (2003)


Question 75 (2003):

When will we have all of the information presented in lectures to be able to do q7? Thanks.

Answer 75:

You have had all the technical knowledge needed for q7 since around week 10 last term. Precise details of what is required by way of animation to get full marks, together with fairly detailed suggestions as to how that may be implemented, is being presented and discussed in the seminar groups (weeks 13-15). Attendance at seminar groups is, of course, compulsory ...

Keywords: q7

2002

Question 37 (2002):

Could you please explain a little more how you would go about implementing the random time delay? I have read through the previous questions on it but I'm still a little lost. Is the time delay between philosophers doing different actions or in the display process?

Answer 37:

It's in the philosopher processes - not the display.

The question says:

Thinking and eating by the philosophers should be modelled by random (but finite!) delays

In the "philosopher" process there are two folds:

  <!--{{{  think-->
  SKIP
  <!--}}}-->

and:

  <!--{{{  eat-->
  SKIP
  <!--}}}-->

You should replace the SKIPs by random delays.

Keywords: q7 , random , timers


Question 36 (2002):

Do we need to design the philosopher system to end "gracefully" like in previous assignments?

Answer 36:

No.

Keywords: q7 , graceful-termination


Question 33 (2002):

Hi, it has been strongly suggested by our seminar leader that we use protocols for the state report channels to the display process. The reports disclose the any change is state from the philosphers, forks and the security guard. Obviously you need to fair multiplex all the philosphers together and all the forks??? However, how can you multiplex three different protocols together??? You can't can you? If not, then I guess we write some display process with three input channels one for each protocol, and work that way.

Answer 33:

Fair mulitplex the philospher reports down to one channel. Same for the forks. That leaves 3 channels, with different protocols, coming to the display process - say a, b and c. To fair-alt those:

  WHILE TRUE
    SEQ
      PRI ALT
        a ? ...
          ...  react to the a mess
        b ? ...
          ...  react to the b mess
        c ? ...
          ...  react to the c mess
      PRI ALT
        b ? ...
          ...  react to the b mess
        c ? ...
          ...  react to the c mess
        a ? ...
          ...  react to the a mess
      PRI ALT
        c ? ...
          ...  react to the c mess
        a ? ...
          ...  react to the a mess
        b ? ...
          ...  react to the b mess

Bit repetitive writing the reaction codes thrice ... so make a PROC for each reaction ... just invoke that PROC thrice.

However, simpler-but-more-dangerous is just to have one protocol that all philosophers, forks and the security guard to use - that's 11 channels, all with the same super-protocol, coming out of the college. Plug those into the display and simply fair-alt that!

It's unsafe to use one protocol for all reports - since a fork, for example, could send a philosopher report by mistake! This is the sort of thing that can happen somewhere down the life-cycle of a product during maintenance. However, for this exercise, you will not lose marks for doing so ... so long as, of course, you don't make any mistakes that this approach allows!

Keywords: q7 , fair-alt


Question 31 (2002):

I would like to use colour in my solution to Q7. The PROC fg.col in shared_screen.occ looks useful ... however, I am unable to use the shared_screen.occ code. I have the following lines at the top of my source code:

  #INCLUDE "shared_screen.occ"
  #USE "shared_screen.inc"

Many errors are generated relating to this, such as:

  Error-oc-shared_screen.occ(337)- pc subscripted too many times
  Serious-oc- Too many errors, maximum is 100.

What am I doing wrong?

Answer 31:

Sorry - we hadn't told you how to use this package. It's not part of the basic "course" library! Before explaining how to access, let me stress that noone needs to find out about and use this stuff - it's only there to provide a rich set of drawing mechanisms for those who want to do some really fancy animation. Even then, you don't have to use it ... but you will end up inventing something similar.

Something anyone could have done is simply copy those two files:

  libsrc/shared_screen.inc
  libsrc/shared_screen.occ

into the start of your own q7.occ file. Then, your own code could simply use anything defined in them. Note that the order is important - the shared_screen.inc must go before the shared_screen.occ file (which uses protocols and data types defined in shared_screen.inc).

Better would be to copy those files into the same directory as your q7.occ file and start your file with:

  #INCLUDE "shared_screen.inc"
  #INCLUDE "shared_screen.occ"

Again, note the ordering! These directives simply tell the compiler to pull in those files at the point of those #INCLUDEs.

Best is not to copy those files at all and use the library. All you haven't been told is the name of the library - which is "ss". Currently, only PROCs and FUNCTIONS are saveable in kroc libraries, which means that constants, data types, prototcols (etc.) have to be pulled in as #INCLUDEs. Anyway, to do this, your file needs to start with:

  #INCLUDE "ss.inc"
  #USE "ss.lib"

These can be followed, or preceeded, by other library accesses - e.g.

  #INCLUDE "consts.inc"       -- standard course library constants
  #USE "course.lib"           -- standard course library

We're not quite done. When compiling, the occam compiler (invoked by the kroc shell script) will find the relevant files. [Note: those working with the Linux kroc need to ensure their OCSEARCH environment variable is set up correctly.] When doing final linking (also invoked by the kroc shell script), we have to tell the linker where to find the library code. In fact, the kroc script uses the standard gcc (Gnu C Compiler) to do this linking - i.e. something different from OCSEARCH happens. Anyway, the compile command needed is:

  kroc q7.occ -lss

Linux users have always had to do something like this to link in the course library (which the kroc script on Solaris machines has been set up to do automatically). So, on Linux, if you want both libraries linked in to your executable, the command is:

  kroc q7.occ -lss -lcourse

Enjoy!

Keywords: q7 , colour , animation


Question 30 (2002):

How many lines of code, rougly, is your solution to q7-dining philosophers?

Answer 30:

The source code for the model answer executable, answers/a7, has 382 lines. These include all the lines in your starter file, exercises/q7.occ, which has 106 lines. So, it can be done with just 276 new lines ...

Keywords: q7


Question 29 (2002):

The random function says that it needs an integer at least 1. At the moment my seed is:

  id + modified.time

I know that my id can equal zero. You said that time could be negative, so I assume that it can equal zero as well. At the moment my modified time is:

  t /\ #7FFFFFFC

I have a vague understanding ofhow this works, but it looks to me that my modified.time can equal zero aswell, making it possible to break the random function. Do I need to change the bitvalue that I /\ with t?

Answer 29:

Your id and the timer value could both be zero - the latter could be negative as well! So, your concerns about the ideas above are valid. Check out the answer to Question 69 (2000), especially David Wood's suggestion at the end.

On a general point, you are strongly advised to browse through the anonymous questions and answers from previous years. On animating the Dining Philosophers, there was much discussion and plenty of good advice. For example, look at Question 68 (2000) ... and lots of others.

Keywords: random , q7

2001

Question 27 (2001):

I am having trouble modifing the fork process in the dining philosopher's question. What I want to do is basically have a fair ALTing process going over the two input lines, left and right.

I have already implemented a fair ALTing process in my animate process, but the difference there was that all the input lines were called the same name -- i.e. state[0], state[1] etc., so implementing it there was easy from the definition given in the notes. The problem with the fork process is that the input lines have two distinct names, and so the definition of fair ALTing does not translate as obviously.

What I have tried to do is give them the same name, so in the fork header I have put '[]CHAN OF BOOL in', but I could not get it to work this way after many attempts. My question is: is this the correct way to be going about altering fork?

Answer 27:

There are two ways. One is to create a channel array abbreviation for the two scaler channels - i.e.

  [2]CHAN OF BOOL c IS [left, right]:

Normal anti-aliasing rules now apply - you can't use the names left and right anymore (because you have the new names, c[0] and c[1], for them). But you now have an array of channels and the usual fair ALTing coding (see slide 10-23) can now be applied.

Second way: don't be clever and just write:

  WHILE TRUE
    SEQ
      PRI ALT              -- first give left priority
        left ? ..
          ..
        right ? ..
          ..
      PRI ALT              -- then give right priority
        right ? ..
          ..
        left ? ..
          ..

Keywords: q7 , fair-alt


Question 26 (2001):

Do we really need the q7 process, because I place my display process in the secure.college process?

Answer 26:

It's the q7 process that has the screen channel, along with the other compulsory channels in its parameter list that are needed for the starting process of the (kroc) occam executable. If you give that parameter signature to your secure.college and make that process the last one in your source code, then that will work fine. But that has bundled up your display process inside your college.

I would prefer the college logic to be independent of its display. That way, we can change the display logic (e.g. to drive some graphics window) without having to touch the college.

Keywords: q7


Question 25 (2001):

For the dining philosophers, I have created my own display process as required. However, I am not sure how to link all the processes together in a network under the q7 process. Any help??

Answer 25:

This is a bit too general a question to answer -- need your source code to point to what you're doing wrong.

All I can offer is this. The q7 process has the screen channel -- plug that into your display along with the (newly declared) report channels, whose other ends are attached to your modified secure.college. Hope that helps.

Keywords: q7


Question 24 (2001):

This is more of an anonymous observation really. I'm sitting here looking at q7.occ and, to be honest, I haven't got the first clue on how to start this assesment. I've been to the lectures and the classes, but me along with quite a few others who I have been talking to over the weekend have got no idea. I appreciate that yes some people have managed to do it, but the others are struggling.

Plus also after talking with my friends we all realised that nobody says anything in the classes apart form a select few which makes for an uncomfortable atmosphere when the postgrad is standing in front of a bunch of students who don't say anything for an hour. Perhaps it would have been better to concentrate more on the dining philosophers assessment in classes? I haven't got many notes on it at all.

Answer 24:

The assessment was set last November, when you had enough technical information to solve it. The occam variant PROTOCOL makes the solution neater and that was introduced by the end of last term. The first two seminar classes this term were devoted to explaining the assessment and talking through the recomended way to solve it. If you 'haven't got many notes on it at all', that is not our fault. That assistance was provided six weeks ago and the assessment could have been completely finished at that time. Last weekend is a bit late to start on this work and complain that you do not know what to do.

Fully participating in seminars is crucial to getting the best out of them. We try to get everyone involved to our best ability and sometimes do not succeed. Sometimes this is our fault. However, if a student has done no preparation for the seminar (e.g. has not worked on the exercises being discussed in between seminars), then that student will find it difficult to contribute to the seminar and will feel uncomfortable.

Keywords: q7


Question 22 (2001):

On slide 6-70 of the occam notes you say:

Modify the fork process so that it guarantees service on each input - even if the other one is perpetually busy. No philospher must starve because of greedy colleagues!

My question is what service should it guarantee on each input? What do you mean by service?

Answer 22:

From a low-level point of view, service in occam always means accepting a channel input. High-level viewpoints depend on the high-level semantics of the process being considered.

In this case, the service performed by a fork is being-picked-up. What needs to be guaranteed is that, if philosopher 3 is sitting next to a continuously ravenous philosopher 2, philosopher 2 doesn't always get the fork. With the given code, there is no such guarantee. Phil 2 could be eating when phil 3 arrives at the table and reaches for the fork it shares with phil 2 and blocks. Eventually, phil2 finishes eating and puts down that fork ... only to become immediately hungry (zero thinking time!) and race back to the table and reach for the fork again. If that happens before the fork process has looped back to the start of its loop, the fork will see both phils trying to pick it up. With a plain ALT, it might let phil 2 pick it up. This could continue for ever!

To eliminate, the fork must fair ALT over those input channels it is servicing.

Keywords: q7


Question 21 (2001):

The function:

  random (maxvalue, seed)

returns an (INT, INT) value. How can I assign the first INT in the pair to one variable, and the second to another? I have tried:

  INT number, seed:
  SEQ
    ...
    (number, seed) := random (maxvalue, seed)

But I imagined it would cause an error ... and it did.

Answer 21:

If you look at the syntax of the function declaration:

  INT, INT FUNCTION random (VAL INT upto, seed)

you will see that it returns an INT, INT - i.e. no brackets! The correct syntax, therefore, is:

    number, seed := random (maxvalue, seed)

For further information on this function, see Question 77 (2000). For general questions about animating the Dining Philosphers' problem, see last year's Question 66 (2000) onwards.

Keywords: q7 , random

2000

Question 92 (2000):

I am doing my own implementation of the q7 (i.e not using any of the methods part written). I won't be docked marks because of this (presuming that my implementation is correct)?

Answer 92:

No - that's perfectly in order.

Keywords: q7


Question 89 (2000):

When drawing the network diagram, do we have to show it as all the philosophers sitting round the table, with the all forks and all the channels - i.e. from the college perspective? Or do we have to draw it as the code we have written - i.e. 1 philosopher, 1 fork, security guard and display taking in channels from those 3 objects?

Answer 89:

For each process implemented as a network of processes, you must draw that network showing all connections - i.e. all internal processes, how they are wired together and/or wired to the outside world. If your network topology for the college reflects the college geopgraphy (e.g. philosophers and forks arranged round a table), that's a nice bonus but not essential.

There will be at least two layers of network to draw - the (secure) college network and the q7 network, consisting of the college and display processes. Each network should be drawn separately - do not try to combine two layers of network on one diagram. Ideally, you should also draw individual process icons for each process (e.g. philosopher, fork, security guard, secure college and display) that shows the shape you are using for that process and its external wires (labelled with the relevant formal parameter names used in your code). All wires should be arrowed to show the direction of data flow and labelled with the channel names used in your program. All processes should be labelled with the process names used in your program (plus any non-channel formal parameters).

Keywords: q7 , diagrams


Question 87 (2000):

The following code:

  PROC displaying ([]CHAN OF DISPLAY d, ...)
    WHILE TRUE
      ALT i = 0 FOR 6
        d[i] ? CASE
          thinking
            out.string ("Philosopher is thinking", 25, out)
          hungry
            out.string ("Philosopher is hungry", 25, out)
          ...  etc.

keeps giving me the error:

    Not enough items in i/o list.

Why does it do that?

Answer 87:

Because there are not enough items in your i/o list. Your DISPLAY protocol must contain variants that contain something other than just a tag name - maybe:

  PROTOCOL DISPLAY
    CASE
      thinking; INT
      hungry; INT
      ...  etc.
  :

In which case, your CASE input must provide the necessary variables for the relevant variant lines. For example:

        d[i] ? CASE
          INT id:
          thinking; id
            ...  make the report
          INT id:
          hungry; id
            ...  make the report
          ...  etc.

Keywords: q7 , protocol


Question 86 (2000):

In a replicated ALT over an array of channels, how do you include a SKIP process to deal with when none of the channels is sending data? For example:

    forks[f] ? CASE
      upfork
        SEQ
          ...  display an fork in the up position
      downfork
        SEQ
          ...  display an fork in the down position
      -- needs a SKIP if none of the forks positions have changed...

I think my program is deadlocking because it keeps waiting for forks to report when none of them have changed position.

Answer 86:

You should not need such a SKIP guard. The best thing for your display process to do when nothing is being reporting is nothing, which is what will happen if you just listen to all the report channels with a replicated ALT. If your program is deadlocking, it is for another reason - such as your college processes (philosophers, forks and security guard) outputting to parameter channels that are not correctly wired to the input channels of your display process.

If you really need to poll all those report channels (and you don't - honest), you could write something like this:

    WHILE TRUE
      PRI ALT
        ALT p = 0 FOR n.phils
          phils[p] ? CASE
            ...  deal with philosopher reports
        ALT f = 0 FOR n.forks
          forks[f] ? CASE
            ...  deal with fork reports
        INT n.sat.down:
        security ? n.sat.down
          ...  deal with this report from the security guard
        TRUE & SKIP
          ...  no reports available - do something else (like SKIP :-()

Keywords: q7 , alternation


Question 85 (2000):

I have expanded my dining philosophers animation network like this:

  [5]CHAN OF PHILOSOPHER a:
  [5]CHAN OF FORK b:
  PAR
    secure.college (a, b)
    display (a, b, screen)

but the compiler is telling me:

    Aliasing error, 'screen' is a free variable.

Any thoughts?

Answer 85:

Yes. It must be the case that your display process does not name its third parameter screen, but nevertheless outputs to a channel called screen. Something like:

  PROC display ([5]CHAN OF PHILOSOPHER from.phil,
                [5]CHAN OF FORK b,
                CHAN OF BYTE out)
    ...  and in here outputs to the 'screen' channel instead of 'out'
  :

Now, this PROC compiles because screen is a globally visibly channel carrying the right protocol (BYTE). It must also be the case that that channel exists because you have declared display inside the body of your main q7 process, where screen is declared as a parameter. [If it had been declared on its own before your main q7 process, it would not have compiled - complaining instead about the unknown channel called screen, which would have been nice.]

Assuming the above, when the compiler came to the attempted instance:

    display (a, b, screen)

it would see an attempt to associate the real channel screen with the formal parameter out. But the compiler knows that your display outputs to this screen directly - so that the process would have two names for the same channel: out and screen. occam does not allow such aliases to happen - hence the error message.

Keywords: q7 , free-variable


Question 82 (2000):

I am attempting to plex together multiple channels into one. Each channel uses a tagged protocol, STATUS, that I have defined. I have found a working solution:

  PROC plex ([]CHAN OF STATUS in, CHAN OF STATUS out)
    WHILE TRUE
      ALT i = 0 FOR SIZE in
        in[i] ? CASE
          INT v:
          sitting; v
            out ! sitting; v
          thinking;
            out ! thinking
          ...  same for all the other variants

However, I am not happy with this, since I am just switching based on what's in the protocol, and just outputting it in every case. What I want to be able to do is something like:

  PROC plex ([]CHAN OF STATUS in, CHAN OF STATUS out)
    WHILE TRUE
      ALT i = 0 FOR SIZE in
        STATUS s:
        in[i] ? s
          out ! s
  :

All my attempts at this have failed, usually resulting in:

    Error-oc-myq7.occ(117)- Name STATUS is not a TYPE.

Can you point me at the right syntax for this? Thanks.

Answer 82:

Your question is a very good one. I'm afraid that occam2.1 has no syntax to express your perfectly reasonable request! This problem occurs when writing many standard components for handling variant (CASE) protocols - buffers, message routers as well as multiplexors and de-mutiplexors. The proposed, but so far unimplemented, occam3 language enabled the declaration of UNION data-types, that would mostly solve this problem. The draft occam3 language specification can be found on:

    http://wotug.ukc.ac.uk/parallel/occam/documentation/

for those interested (1.4 MBytes postscript). Summer or group project anyone?

Keywords: q7 , multiplex


Question 81 (2000):

For the Dining Philosopers Animation, can we get full or nearly full marks with a simple text output describing each state change?

Answer 81:

Around 20% of the marks are for a decent animation - where decent means at least to the standard of that given by:

    /usr/local/work/co516/answers/a7  (on raptor)

Keywords: q7


Question 80 (2000):

The question says:

"Thinking and eating by the philosphers should be modelled by random (but finite!) delays."

Assuming we have obtained a random number, what's the best way to implement the delay ... i.e. pause execution for a random time? Is there a wait(time) function or such like?

Answer 80:

See slide 4-40 and sections 3.4/3.5 of the "OCCAM2 CHECKLIST" paper. Spelling it out:

  TIMER tim:
  INT t:
  SEQ
    tim ? t
    tim ? AFTER t PLUS waiting.time

Keywords: q7 , timers

Referrers: Question 59 (2004)


Question 77 (2000):

Ok, I am confused. What's the deal with all the seed things? Also what's the deal with the animation? Where can I find some examples of some coding for screen display?

[I'm combining this question with the following one (PHW)]

Please could you tell me how to generate a random number in occam? I've forgotten and can't find it in the notes. Thanks.

Answer 77:

All these things have been explained in your seminar groups. I'll just point you at Question 76 (2000) for information about implementing the screen display and:

    /usr/local/work/co516/libsrc/random.occ

for information about the random number generating FUNCTION, for which you need to set up and maintain a seed variable.

Keywords: random , q7

Referrers: Question 21 (2001)


Question 76 (2000):

I think we've already been told, but where are we meant to find the documentation on all the methods we need for the display process, in order to move the cursor around the screen etc?

Answer 76:

Yes - you have been told! See, on raptor, files:

    /usr/local/work/co516/libsrc/utils.doc

which is a text file (not an MS-Word document!). The procedures you want are documented at the end of the file, following the comment (fold) line:

    ...  screen stuff (VT220 protocol)

Alternatively, you could browse the full source code:

    /usr/local/work/co516/libsrc/utils.occ

There's also a simple demo of the cursor.x.y procedure in:

    /usr/local/work/co516/examples/test_utils.occ

Keywords: q7 , display

Referrers: Question 77 (2000) , Question 78 (2000)


Question 75 (2000):

I get a compiler error when I adpated the philosopher's process to accommodate the sending of data when the philosopher does an action. It says that within a PAR scope, I cannot output to the same report channel (to the display process) in parallel branches of the PAR. Which is fair enough. But how can I get past this?

Answer 75:

One way is to put in two report channels from the philosopher and, then, either a separate multiplexor process that merges those two down to one or just take both report channels to the display process (which will get a bigger array of input channels to service).

Better, though, is to get your fork processes to have report channels to the display. Then, don't bother reporting fork acquisitions from the philosopher (which is, I guess is what you were trying to do in parallel - because the fork acquisitions occur in parallel). The forks can report where they are directly on their own report channels.

Keywords: q7 , parallel-output


Question 72 (2000):

When I recieve the appropiate case statement, I want to output a string. But what command does that?

Answer 72:

It sounds like you don't know about:

  out.string ("any old string", fieldwidth, screen.channel)

from the course library? Look at any of the examples in your examples directory on raptor - or the answers directory at:

    /usr/local/work/co516/answers/

Keywords: q7


Question 71 (2000):

When tapping the channels for the philosophers and forks, Fred recommended giving each one an id. If it were Java, I would simply assign each object an individual id when their constructor was called. Can I do something similar in occam?

Answer 71:

Yes. To set up a number, say n, of thing processes and give each instance its own id is easy. First, the PROC header for a thing must take an id parameter - for example:

  PROC thing (VAL INT id, ...)
    ...  body of thing
  :

Then, to set up the instances:

  PAR i = 0 FOR n
    thing (i, ...)

That's all.

Keywords: q7


Question 70 (2000):

Once the first draft of my q7 program is compiled and run, it produces this error:

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

I don't know what this means, so I would be grateful if you could point me in the right direction ...

Answer 70:

It means your program crashed. There are several possible causes of this run-time error:

I'm afraid the message you report is all you get from the KRoC/Solaris system. If you compile this with KRoC/Linux using the command:

    kroc -d myfile.occ -lcourse

it will tell you the file name and line number of the offending line. [Note: the "-lcourse" flag above is just to link in the course library - something which is automatic with the Solaris version of the kroc command. The active ingredient of the above command is the "-d" flag.]

Keywords: q7 , range-error , stop

Referrers: Question 31 (2012) , Question 6 (2011) , Question 53 (2006) , Question 43 (2004) , Question 30 (2003) , Question 86 (2003) , Question 11 (2002)


Question 69 (2000):

In a post, Fred says that the maximum negative 32 bit int is -2147483648, so I have coded appropriately ...

  -- ensure seed is positive & legal
  IF
    seed = (-2147483648)       <---------ERROR!!!
      seed := 2147483647
    seed < 0
      seed := -seed
    seed = 0
      seed := 1
    TRUE
      SKIP

But I get an error on the line arrowed above which says:

          Overflow when evaluating constant expresssion

Help!! Have I done something wrong or is the info on cs2 wrong?

Answer 69:

The compiler treats -2147483648 as an expression, so it gets an error when trying to evaluate 2147483648 (which is larger than the largest INT). If it got past that, it would get another error trying to negate it.

occam has a special way of naming the largest and smallest of any of its number types. For example,

  MOSTNEG INT
  MOSTPOS INT

give you, respectively, the most negative and positive integers. Other ways we can write MOSTNEG INT are:

  #80000000
  1 << 31

But ... my colleague, David Wood, suggests you might like to consider:

  TIMER tim:
  INT seed:
  SEQ
    tim ? seed
    seed := (seed >> 2) + 1

Keywords: inverting , int , random , q7

Referrers: Question 29 (2002)


Question 68 (2000):

I've forgotten how to implement the lookup table for the screen positions for the dining philosophers. Any help would be appreciated.

Answer 68:

Your animation code should not be highly repetitive with the same logic repeated with different magic numbers - e.g. for displaying new positions of the different philosophers. Having a table of anchor coordinates for each philosopher may help. A table is simply an array of VALues (i.e. constants). For example:

  VAL [][2]BYTE phil.anchor IS [[40, 5], [70, 10], [55, 15],
                                [35, 15], [10, 10]]:

where the [][2]BYTE could have just been [][]BYTE, but being specific about the dimension of the coordinates (rather than the number of them) seems right. We could have been even more explicit and written [5][2]BYTE, but that seems too much. Any way, the compiler will fill in the sizes of any blanks in what we write after the IS.

With the above, it's nice to give names to the two indices of the [2]BYTE array coordinates - e.g.

  VAL INT X IS 0:
  VAL INT Y IS 1:

Then, if we want to move the screen cursor to the anchor point for philosopher i - and we know that that i is a valid philosopher number (i.e. 0 through 4):

    cursor.x.y (phil.anchor[i][X], phil.anchor[i][Y], screen)

or, more efficiently:

    VAL [2]BYTE phil.i IS phil.anchor[i]:
    cursor.x.y (phil.i[X], phil.i[Y], screen)

since it only checks the array index (for out-of-bounds error) and calculates the address of phil.anchor[i] once.

Keywords: q7 , cursor , table , animation

Referrers: Question 43 (2009) , Question 30 (2008) , Question 84 (2003) , Question 29 (2002)


Question 67 (2000):

How do I create a replicated protocol CASE statement for the dining philosophers. I have written:

  PROC display ([]CHAN OF MYPROTOCOL reportin, CHAN OF BYTE out)
    WHILE TRUE
      ALT i = 0 FOR 10
        INT n:
        reportin[i]? CASE
          thinking
            out.string ("Philosopher Sat Down", 50, out)
          hungry
            out.string ("Philosopher is hungry", 50, out)
          etc...
  :

But I keep getting incorrect indentation errors. Do I need any SEQ or PARs here or is the problem elsewhere?

Answer 67:

There is nothing illegal with the above code fragment, assuming that your etc... introduces another variant of MYPROTOCOL. Your local (but unused) declaration of INT n, for example, is perfectly legal just above the ALT guard. It could also be located just above (and aligned with) any of the CASE variants if that were useful.

Indentation errors are trivial to correct. Mail me your code and tell me the line number of any indentation errors reported by the compiler and I'll tell you what's wrong. If it's a general point, I'll make up the relevant (anonymous) question and post an answer to these pages.

Keywords: q7 , incorrect-indentation


Question 66 (2000):

For question 7, I am trying to draw a boarder for the dining philosophers room. I can do it with lots of cursor.x.y and out.string procedures but this seems time consuming. I thought of doing it in a replicated PAR or replicated SEQ and I wrote this code:

  #INCLUDE "consts.inc"
  #USE "course.lib"

  PROC a (CHAN OF BYTE out)
    PAR i = 1 FOR 26
      SEQ
        cursor.x.y (4, i, out)
        out.string ("#", 0, out)
  :

  PROC test (CHAN OF BYTE keyboard, screen, error)
    PAR
      a (screen)
      ...  other things
  :

But when I compile it, it says there is a type mismatch in parameter 2 of cursor.x.y. This is the y coordinate that I am changing so that the character gets printed on the line below the first one to create a column like this:

      #
      #
      #
      #
      #
      #

Why does the compiler not like the second parameter of the cursor.x.y proceedure? Doesen't it just need to be a number?

Answer 66:

The second parameter of cursor.x.y needs to be a BYTE. Replicator control variables (e.g. your i) are INTs. You need to cast it into a BYTE:

        cursor.x.y (4, BYTE i, out)

See the answer to Question 7 (2000) for information on casting between occam types.

Your PAR replicator also won't work because it implies parallel outputs to the out channel - illegal! So it has to be a SEQ replicator. In any case, unless the occam kernel supports, and is running on a multiprocessor machine, the SEQ replicator for code like this will be faster than a PAR (which will have to startup and shutdown 25 software processes).

Your code would also be slightly snappier with:

  PROC a (CHAN OF BYTE out)
    SEQ
      cursor.x.y (4, 1, out)
      SEQ i = 1 FOR 26            -- the "2" could be anything though
        SEQ
          out ! '#'               -- don't need out.string for a single char
          cursor.down (1, out)
          cursor.left (1, out)
      out ! FLUSH

Keywords: q7 , type-mismatch , cast , cursor

Referrers: Question 32 (2012) , Question 21 (2001) , Question 74 (2000)

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