This project is a multithreaded Java simulation of a concurrent car wash service station. It implements a classic solution to the Producer-Consumer Problem using a bounded buffer and custom semaphores to manage thread safety and resource allocation.
The core logic was developed as part of the CS241: Operating System curriculum at Cairo University, Faculty of Computers and Artificial Intelligence.
The members and their specific contributions are listed below.
| Name | Contribution |
|---|---|
| George Ezzat Hosni | Implemented ServiceStation (Main class, input, and thread orchestration). |
| Doha Fathy Refaey | Implemented the custom Semaphore class (using wait()/notify()). |
| Nagham Sabry Ahmed | Implemented the Pump (Consumer) thread logic. |
| Marym Ali Abdelkarym | Implemented the Car (Producer) thread logic. |
The simulation models a service station with a limited number of service bays and a fixed-size waiting area.
-
Cars (Producers): Arrive at the station as
Carthreads. -
Waiting Area (Bounded Buffer): Cars enter a
waitingQueue(the buffer). If the queue is full, theCarthread blocks until a spot is free. -
Pumps (Consumers): A fixed number (
N) ofPumpthreads run concurrently. They block if the queue is empty (full.semaphoreWait()). -
Service Bays (Resource Semaphore): After a
Pumptakes a car from the queue, it must also acquire a free service bay. A separatepumpssemaphore manages this, ensuring onlyNcars can be serviced at the same time.
The core of this project is the correct management of two distinct shared resources: the waiting spots in the queue and the service bays themselves.
This is achieved using four semaphores, all custom-built using Java's wait() and notify().
| Semaphore | Initial Value | Purpose |
|---|---|---|
mutex |
1 |
Mutual Exclusion: A binary semaphore that ensures only one thread (Car or Pump) can access the waitingQueue at a time. |
empty |
waitingAreaCapacity |
Tracks empty spots: A counting semaphore that tracks the number of free spots in the queue. Car threads wait() on this. |
full |
0 |
Tracks items: A counting semaphore that tracks the number of cars in the queue. Pump threads wait() on this. |
pumps |
numPumps |
Tracks resources: A counting semaphore that tracks the number of available service bays. Pump threads wait() on this after taking a car from the queue. |
The Pump threads are set as daemon threads (pumpThread.setDaemon(true)). This is a critical design choice that allows the simulation to shut down cleanly and automatically once the main thread and all (non-daemon) Car threads have finished executing.
The application is contained within a single ServiceStation.java file, which includes four main classes:
-
ServiceStation: The main class. It handles user input, initializes all semaphores and the shared queue, creates and starts thePumpandCarthreads. -
Semaphore: A custom-built semaphore class that implements thesemaphoreWait()(P) andsemaphoreSignal()(V) operations usingsynchronized,wait(), andnotify(). -
Car(Producer): ARunnableclass that represents an arriving car. Itsrun()method implements the producer logic: wait for an empty spot, lock the queue, add itself, unlock the queue, and signal that the queue is no longer empty. -
Pump(Consumer): ARunnableclass that represents a service bay. Itsrun()method implements the consumer logic: wait for a full spot, lock the queue, take a car, unlock the queue, signal that a spot is now empty, wait for a free pump, service the car, and finally release the pump.