Snail Gate Project

by: burt rosenberg
at: september 2022

Overview

This project is a fun project with three serious goals,

  1. To introduce thread programming,
  2. To show how condition-wait works,
  3. To show the techniques of data sharing between threads in a process.
A draw thread is launched, which loops at a certain rate, incrementing the snail and drawing a picture of it, and a gate. The gate is either open and closed. If the gate is open when the snail arrives it passes through and eventually the game is won. Else the snail smushes against the gate and the game is lost.

The Snail Gate Game

The nag program

Man page

NAME
   snail --- the snail gate game
      
SYNOPSIS

    snail [-v]

DESCRIPTION

   As the snail moves towards a gate, the user guesses the one digit key to the 
   door. If the user guesses the key, the door opens (depicted by the ? in the 
   gate disappearing) and the snail can pass through the gate.
 
OPTIONS

    -v verbose
     
ARGUMENTS

    None

OUTPUT
  
    A graphic with a snail @/, an closed gate [?] and an open gate [ ].
    
HISTORY

    New for csc421-231.

    

The nag program, github://csc-courses/csc421/nag.c, is the basis for this project. The nag routine is a thread that from time to time wakes up and checks if something new has been said. If not it nags the user to say something. However if so, it insults the user for what they said.

Note in this program,

  1. The thread is launched in the main route with pthread_create().
  2. The main and nag threads communicate through a struct T_arg, passed to the nag thread on creation.
  3. Use of data in common between the nag and main thread is synchronized by being placed inside a block beginning with pthread_mutex_lock() and ending with pthread_mutex_lock().
  4. The nag thread waits by calling pthread_cond_timedwait(), taking three arguments,
    1. The mutex to wait on, of type pthread_mutex_t,
    2. The condition signal to listen for, of type pthread_cond_t,
    3. A timer value for the time-out, struct timespec.
  5. The main thread can signal thread nag thread on the pthread_cond_t by calling pthread_cond_signal().
  6. The nag thread knows whether the shared buffer data is new or old by comparing a counter that is set by the main thread with an older value that is saved by the nag thread.
  7. The exit is asked for by the main by way of a request variable, req_exit, and the effective acknowledgement is by the main waiting for the thread's call to pthread_exit by its own call to pthread_exit.

Data structures

The nag and main threads communicates by two methods,

  1. by an anonymously typed argument to the thread when created,
  2. and a global struct of type struct Board.
The two ways were given so to illustrate how threads share a single dataspace. The globals are known between them; and a reference that they have, dereferences to the same data.

 struct Board {
	int snail_loc ;
	char guess ;
	int gate_loc ;
	int gate_key ;
	int gate_state ;
	} ;

struct T_arg {
 	int req_exit ;
 	pthread_mutex_t * mutex ;
 	pthread_cond_t * cond  ;
 	} ;

The board information is held in a global struct of type struct Board. The snail has advanced to integer position snail_loc. The main thread update guess with what the user has guessed. The get is located at gate_loc and is opened by the character gate_key. The gate_key takes one of two values, GATE_IS_CLOSED or GATE_IS_OPEN. This field is used when creating the string tha represents the game.

There are good reasons not to use globals. Keeping track of data is the most important thing in code, so keeping access to data focused is very helpful. The utility code, snail-util.c does not refer to board as a global but is passed in a reference to the global.

I also took this opportunity to exercise how a struct is accessed either directly with the dot or through a pointer with the arrow. By the way, the arrow is simply a convenience, as it is a short had for using the dereferencing star on the pointer, followed by field selecting dot.

    p->f  is the same as *p.f but just more fun to write (Harbison & Steele 2nd Ed. 7.4.2 p 149).
The mutex information is shared through a struct T_arg with a shared pointer, passed into the thread coerced downwards (towards a generic) as a void * then upcast back to it's true type of a struct T_arg *.

snail-util.c

You have been provided with utility functions to draw the game board. You task is merge this with what you know from nag.c to communication in a thread safe manner between the main "controller" thread and the draw "viewer" thread. The "model" is latent in the data structures, which are shared between viewer and controller.

Note in the Makefile,

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

author: burton rosenberg
created: 20 sep 2022
update: 21 sep 2022