Jump to content

Photo

Concurrent processes in Pascal


3 replies to this topic

#1 Rossman OFFLINE  

Rossman

    Space Invader

  • 41 posts

Posted Thu Nov 9, 2017 11:45 PM

Anything worth engineering is worth over-engineering!  Er, no, I am pretty sure that is not correct.  Difficult to debug... difficult to maintain... Hmmm. 

 

Well, ok, maybe not.  But over-engineering is a lot of fun!

 

Just for sake of researching it - and because I was not looking forward to refactoring my game logic - I decided to investigate how I could reduce the delay created at startup by shuffling 4 decks at game start.  So I created a little model program of concurrent processes.  One process fills an array (as fast as it can, up to 2,000 values).  The other process reads from the array (no more than 6 values at a time).  Essentially, I seed the array with 6 values and then go concurrent.  I believe I need to implement a semaphore so the second process does not read ahead of the first process writing.

 

So that I would know that Things Are Happening in my concurrent processes, it seemed to me that I could create a little visual cue that each process was stepping through.  I did this:

 

 
program contest;
 
type
  valstack = array[0..1999] of integer;
  sixcards = array[0..5] of integer;
 
var
  valyoos : valstack;
  onehand, showhand : semaphore;
  cards : sixcards;
  mainpoint : integer;
 
process defvalyoo;
 
var
  x : integer;
  sc : char;
 
begin
 
...
 
  while x <= 1999 do begin
    wait(onehand);
    valyoos[x] := x;
    x := x + 1;
    gotoxy(12,12);
    write(sc);
    if (sc = '-') then 
      sc := '|'
    else
      sc := '-'; 
    signal(showhand);
  end;
end;
 
process gethand;
 
var
  t, y : integer;
  cardo : array[0..5] of integer;
  tc : char;
 
begin
 
...
 
  while t < 4 do begin
    y := 0;
    while y <= 5 do begin
      wait(showhand);
      cardo[y] := valyoos[mainpoint];
      y := y + 1;
      mainpoint := mainpoint + 1;
      signal(onehand);
    end;
    y := 0;
    while y <= 5 do begin
      wait(showhand);
      y := y + 1;
      gotoxy(15,12);
      write(tc);
      if (tc = '*') then
        tc := '-'
      else
        tc = '*';
      signal(onehand);
    end;
end;
 
begin
  seminit(onehand,0);
  seminit(showhand,1);
  start(defvalyoo);
  start(gethand);
  ...
end.
 
And this worked.  Well, it worked as far as the limits of the nested loops in showhand.  I failed to work out the fact that the consume-the-array (gethand) process would expire and therefore prevent the fill the array process (defvalyoo) from fulfilling its potential (of 2,000 array updates) by way of semaphore.  But, my little concurrent experiment worked.  I have little spinners going a few characters apart in row 12, simultaneously.  It's kinda cool.
 
But...
 
If I try to write out the value of an integer or array variable within a process, I get a stack overflow error.
 
For example, In gethand, instead of doing the write(tc) and if logic that follows, if I have 
    write('Card: ', cardo[y]);
 
or 
    write('Card: ', y); 
 
I get a stack overflow error at runtime on the first write attempt.  I get Card: **STACK OVERFLOW**  at runtime.  And then I have to do an unhappy warm restart.
 
What seems interesting to me is that I can WRITE (as a verb) by proxy.  The variable tc type char, who's state is derived from a previous state of itself.  It spins, which indicates the code logic appears to be stepping through.  The spinners run in fits and starts as I would expect, side-by-side. 
 
But I cannot write a variable value that is an integer or an array value.  It doesn't matter whether it is a local (cardo[y], or y) or global (valyoos[mainpoint-1], or mainpoint).  I get a **STACK OVERFLOW** at runtime.
 
This could be (and likely is) a monumentally stupid error on my part (it would not be the first time). But it seems odd to me that I can write by proxy, but not by value.  The logic is executing and not failing. But it feels a bit like Heisenberg's uncertainty principle applied..
 
Concurrency isn't essential to my little program, but it might expedite startup.  And, to make this practical, I will have to make my game logic process along side the card logic and, possibly, along side the wagering logic (not yet implemented).  
 
It is over-engineering.  But it is also lots of fun to experiment with.  Anybody run into this themselves?
 
 
 


#2 TheBF OFFLINE  

TheBF

    Moonsweeper

  • 370 posts
  • Location:The Great White North

Posted Fri Nov 10, 2017 8:02 AM

I have not used the Pascal system on TI but I am wondering if the documentation explains stack usage per process?

 

Could it be that the stack size is set somewhere at start up and its a shared stack space that gets consumed in chunks by each process? This might leave your print code with nothing left to format a number to text.

 

Full on conjecture here.



#3 apersson850 ONLINE  

apersson850

    Moonsweeper

  • 436 posts

Posted Sat Nov 11, 2017 2:06 PM

In UCSD Pascal, each process has its own stack space. By default, it's 200 words. This may not be enough to hold local variables and the activation record of the system calls to the write procedure, including that procedure's local data.

Try increasing the stack space to, say, 400 words and see if it makes a difference. You do that by adding parameters to the start statement.

var
  pid: processid;

process myprocess;

begin
....
writeln(something);
...
end;


begin
.....
start(myprocess, pid, 400);
...
end.

Processid is a predeclared type. It's used here only because the stack size is the third parameter to the start command, so you have to fill it out with getting a process id you don't need. Unless you want to start messing with the internals of the concurrency support.


Edited by apersson850, Sat Nov 11, 2017 2:06 PM.


#4 Rossman OFFLINE  

Rossman

    Space Invader

  • Topic Starter
  • 41 posts

Posted Sun Nov 12, 2017 11:36 PM

In UCSD Pascal, each process has its own stack space. By default, it's 200 words. This may not be enough to hold local variables and the activation record of the system calls to the write procedure, including that procedure's local data.

Try increasing the stack space to, say, 400 words and see if it makes a difference. You do that by adding parameters to the start statement.

 

Could it be that the stack size is set somewhere at start up and its a shared stack space that gets consumed in chunks by each process? This might leave your print code with nothing left to format a number to text.

 

 

 

Thanks to both of you for the suggestions.  I have not followed-up yet.  Investigating concurrency gave me the luxury of putting off an unpleasant refactoring of my core game logic!  I bit the bullet and got on with refactoring.  I'm about half-way through it, and it is going well.  The code is better organized, and more read-able, and better encapsulated. Have one major unwind yet to go.

 

I will revisit my concurrency experiment during the week and let you know how it turns out.  For what it's worth, I was pleasantly surprised with how far I was able to push my concurrency experiment.  

 

Again, thank you for the tip.  I hadn't thought about the stack size.






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users