Purpose: to understand thread synchronization in an event-driven workflow using standard C and pthread library in Linux. To experience resource allocation issue.

Description: Your task is to write a 'server' program handling ticket sales using threads. Imagine we are going to sell tickets for a Las Vegas show called OShow. The theater has 10 kiosks for ticket sales. Each kiosk connects to a central server, on which your ticket sales program is running.

Figure: see image.

The show has 4 different seating categories: Floor, Mezzanine, Balcony, and Box. The number of seats available and prices are as follows:

Floor Mezzanine Balcony Box
Total seats 110 80 90 40
Price $210 $130 $100 $230

Patrons can come to any of the kiosks to purchase tickets. Once a patron comes up to a kiosk, the purchase transaction proceeds as follows:

1) The patron first asks for a price quote for a seating by showing "QUOTE_ME_< SEATNAME>" message.

2) If seat is available, the kiosk replies by showing the price. If seat is sold-out for the requested seating area, it replies by "TICKET_SOLD_OUT" message instead of price quote.

3) If the patron receives price quote, the patron can either accept to buy the ticket (by showing "I_ACCEPT" message) or reject the quote (by showing I_REJECT). In the case the patron received sold-out message in 2), the sales transaction is completed at this point.

4) The kiosk responds to patron's decision made in 3) by sending out a unique ticket sequence number back to patron in case "I_ACCEPT", or a special message REJECT_ACKNOWLEDGED in case I_REJECT. This completes the sales transaction.

Note that the kiosk must deliver a ticket that's quoted and accepted. This means at step 4) we dont have message like "sorry, the ticket I quoted you just went away". It must deliver unique ticket sequence number.

Figures below illustrate the above transaction protocol.

Figure 1. Messages sent when client successfully purchases a floor level ticket. see image.

Figure 2. Messages sent when client quoted a price for balcony seat, but rejected the quote. see image.

Figure 3. Messages sent when client asks for a quote for a seating area that has been sold out. see image.

Figure 1 shows the sequence of messages when client purchases a floor level ticket. Figure 2 illustrates the case when client reject the price quote. Figure 3 shows the case when ticket for a particular seating area has been sold out.

Once a TICKET_SOLD_OUT message for a particular seating category is notified at a particular kiosk, patrons will not ask for quote anymore for that category at that kiosk. (the kiosk hangs a sign like 'Balcony sold out'). Once kiosk knows that all the four seating categories are sold out, the kiosk shuts down and communication lines will be closed (see details section below).

We assume that patrons can buy only one ticket at a time. Also, the show is very popular - there are infinite demands for the seats so the show will be sold out always.

Patrons are also very patient, meaning that they can wait indefinitely for a price quote. In other words, after step 1), the kiosk can take arbitrarily long time to show quote at step 2). This is important because, if not careful, you won't be able to guarantee the delivery of a ticket quoted when tickets are almost sold out. Be careful NOT TO OVERSELL the tickets.

Details: The above description is simulated by two programs: 'oshow' and patrons. Oshow is the multi-threaded server program that handles ticket sales. Oshow spawns 10 threads. Each thread represents one kiosk. Your task is to implement the oshow program.

The patrons program simulates customers buying tickets by interacting with oshow via named pipe (described below). I provide the patrons program.

The IPC (Inter-Process-Communication) needed in this setup is satisfied by using 'fifo' also known as named pipe. fifo allows you to create a file system entry that is not actually backed by a physical file in storage: the entry is used as a means of communication between two processes. Once you have a fifo entry in the file system (e.g., $ mkfifo my_fifo creates my_fifo in current dirctory), then a program A can open the file read-only, then a program B can open the file write-only. What program B writes to the file will appear at program As reads. For details, see man pages for fifo(7), mkfifo(1), and fifo-specific sections on open(2), read(2), write(2).

Unlike socket, fifo/named pipe is half-duplex: you need two fifos to implement bidirectional communication. Each kiosk-patron connection is thus represented by a pair of fifo:

  • kiosk-client[0-9] is used for messages sent from patron to kiosk
  • kiosk-server[0-9] is used for messages sent from kiosk to patron

This means that you need to create total 20 fifos in your working directory. To help you set up your directory, the Makefile included has a target named 'fifos' which creates all 20 fifos in current directory. (i.e., "$ make fifos" command in shell will create the fifos.)

The format of message packets sent through the fifos is very simple: each packet is just 4-byte signed integer in little-endian. Interpretation of the value depends on context (See the figures above for example). Following lists #define s symbols for special values:

// messages from client (patron)
#define QUOTE_ME_FLOOR (1)
#define QUOTE_ME_MEZZANINE (2)
#define QUOTE_ME_BALCONY (3)
#define QUOTE_ME_BOX (4)
#define I_ACCEPT (11)
#define I_REJECT (12)

// special values from server (kiosk)
#define TICKET_SOLD_OUT (-1)
#define REJECT_ACKNOWLEDGED (-2)

When you work on the project and want to test and debug, you need to execute the server (oshow) and the client (patron) programs concurrently. This means that you will need to set up two ssh terminal screens so that you launch oshow in one screen and patron on another screen. You may want to have third screen just to code/debug. Or, you can use some terminal management programs such as 'screen'.

You don't have to modify patron.c . Of course you can change patron.c if you wish, for example, when you want to debug your oshow code and you want to add more test routines/debug outputs on patron.c . However, make sure that your final code works correctly with the original patron.c

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.