7 Commits

Author SHA1 Message Date
Gaa56
a31ac61a9a Start traffic light threads on process initialization 2025-11-07 12:14:52 +00:00
5dc1b40c88 Merge pull request #32 from davidalves04/14-create-trafficlightthread-class
14 create trafficlightthread class
2025-11-06 13:53:12 +00:00
3117bdf332 Merge branch 'dev' into 14-create-trafficlightthread-class 2025-11-06 13:53:01 +00:00
1140c3ca48 Merge pull request #30 from davidalves04/13-create-exit-node-process
13 create exit node process
2025-11-06 13:49:21 +00:00
Gaa56
484cba1eee Update TrafficLightThread 2025-11-05 13:21:10 +00:00
Gaa56
0e5526c3f6 Merge pull request #31 from davidalves04/dev
Dev
2025-11-05 12:37:48 +00:00
Gaa56
4710c96450 Create TrafficLightThread Class 2025-10-30 18:06:02 +00:00
2 changed files with 167 additions and 118 deletions

View File

@@ -12,10 +12,10 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import sd.config.SimulationConfig;
import sd.engine.TrafficLightThread;
import sd.model.Intersection;
import sd.model.MessageType;
import sd.model.TrafficLight;
import sd.model.TrafficLightState;
import sd.model.Vehicle;
import sd.protocol.MessageProtocol;
import sd.protocol.SocketConnection;
@@ -173,137 +173,28 @@ public class IntersectionProcess {
* Starts all traffic light threads.
*/
private void startTrafficLights() {
System.out.println("\n[" + intersectionId + "] Starting traffic light threads...");
System.out.println("\n[" + intersectionId + "] Starting traffic light threads...");
for (TrafficLight light : intersection.getTrafficLights()) {
trafficLightPool.submit(() -> runTrafficLightCycle(light));
TrafficLightThread lightTask = new TrafficLightThread(light, this, config);
trafficLightPool.submit(lightTask);
System.out.println(" Started thread for: " + light.getDirection());
}
}
/**
* The main loop for a traffic light thread.
* Continuously cycles between green and red states.
*
* only one traffic light can be green at any given time in this intersection.
*
* @param light The traffic light to control.
*/
private void runTrafficLightCycle(TrafficLight light) {
System.out.println("[" + light.getId() + "] Traffic light thread started.");
while (running) {
try {
// Acquire coordination lock to become green
trafficCoordinationLock.lock();
try {
// Wait until no other direction is green
while (currentGreenDirection != null && running) {
trafficCoordinationLock.unlock();
Thread.sleep(100); // Brief wait before retrying
trafficCoordinationLock.lock();
}
if (!running) {
break; // Exit if shutting down
}
// Mark this direction as the current green light
currentGreenDirection = light.getDirection();
light.changeState(TrafficLightState.GREEN);
System.out.println("[" + light.getId() + "] State: GREEN");
} finally {
trafficCoordinationLock.unlock();
}
// Process vehicles while green
processGreenLight(light);
// Wait for green duration
Thread.sleep((long) (light.getGreenTime() * 1000));
// Release coordination lock (turn red)
trafficCoordinationLock.lock();
try {
light.changeState(TrafficLightState.RED);
currentGreenDirection = null; // Release exclusive access
System.out.println("[" + light.getId() + "] State: RED (RELEASED ACCESS)");
} finally {
trafficCoordinationLock.unlock();
}
// Wait for red duration
Thread.sleep((long) (light.getRedTime() * 1000));
} catch (InterruptedException e) {
System.out.println("[" + light.getId() + "] Traffic light thread interrupted.");
break;
}
}
System.out.println("[" + light.getId() + "] Traffic light thread stopped.");
}
/**
* Processes vehicles when a traffic light is GREEN.
* Dequeues vehicles and sends them to their next destination.
*
* @param light The traffic light that is currently green.
*/
private void processGreenLight(TrafficLight light) {
while (light.getState() == TrafficLightState.GREEN && light.getQueueSize() > 0) {
Vehicle vehicle = light.removeVehicle();
if (vehicle != null) {
// Get crossing time based on vehicle type
double crossingTime = getCrossingTimeForVehicle(vehicle);
// Simulate crossing time
try {
Thread.sleep((long) (crossingTime * 1000));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// Update vehicle statistics
vehicle.addCrossingTime(crossingTime);
// Update intersection statistics
intersection.incrementVehiclesSent();
// Send vehicle to next destination
sendVehicleToNextDestination(vehicle);
}
}
}
/**
* Gets the crossing time for a vehicle based on its type.
*
* @param vehicle The vehicle.
* @return The crossing time in seconds.
*/
private double getCrossingTimeForVehicle(Vehicle vehicle) {
switch (vehicle.getType()) {
case BIKE:
return config.getBikeVehicleCrossingTime();
case LIGHT:
return config.getLightVehicleCrossingTime();
case HEAVY:
return config.getHeavyVehicleCrossingTime();
default:
return config.getLightVehicleCrossingTime();
}
}
/**
* Sends a vehicle to its next destination via socket connection.
*
* @param vehicle The vehicle that has crossed this intersection.
*/
private void sendVehicleToNextDestination(Vehicle vehicle) {
public void sendVehicleToNextDestination(Vehicle vehicle) {
String nextDestination = vehicle.getCurrentDestination();
try {

View File

@@ -0,0 +1,158 @@
package sd.engine;
import sd.IntersectionProcess;
import sd.config.SimulationConfig;
import sd.model.TrafficLight;
import sd.model.TrafficLightState;
import sd.model.Vehicle;
/**
* Implements the control logic for a single TrafficLight
* as a Runnable task that runs in its own Thread.
*
*/
public class TrafficLightThread implements Runnable {
/**
* The TrafficLight object (the *model*) that this thread controls.
* Contains the queue and the state.
*/
private final TrafficLight light;
/**
* The IntersectionProcess (the Process) that "owns" this thread.
* Used to call methods on the process, such as sendVehicleToNextDestination().
*/
private final IntersectionProcess process;
/**
* The simulation configuration, used to get timings (e.g., crossing time).
*/
private final SimulationConfig config;
/**
* Volatile flag to control the graceful shutdown mechanism.
* When set to 'false', the 'run()' loop terminates.
*/
private volatile boolean running;
/**
* Constructor for the Traffic Light Thread.
*
* @param light The TrafficLight object (model) to be controlled.
* @param process The parent IntersectionProcess (for callbacks).
* @param config The simulation configuration (to get timings).
*/
public TrafficLightThread(TrafficLight light, IntersectionProcess process, SimulationConfig config) {
this.light = light;
this.process = process;
this.config = config;
this.running = false; // Starts as 'stopped'
}
/**
* The main entry point for the thread.
* Implements the GREEN/RED cycle logic extracted from IntersectionProcess.
*
*/
@Override
public void run() {
this.running = true;
System.out.println("[" + light.getId() + "] Traffic light thread started.");
try {
// Main thread loop, continues while 'running' is true
// This 'running' flag is controlled by the parent IntersectionProcess
while (running) {
// --- GREEN Phase ---
light.changeState(TrafficLightState.GREEN); //
System.out.println("[" + light.getId() + "] State: GREEN");
// Process vehicles in the queue
processGreenLightQueue();
// Wait for green duration
Thread.sleep((long) (light.getGreenTime() * 1000)); //
if (!running) break; // Check flag after sleep
// --- RED Phase ---
light.changeState(TrafficLightState.RED); //
System.out.println("[" + light.getId() + "] State: RED");
// Wait for red duration
Thread.sleep((long) (light.getRedTime() * 1000)); //
}
} catch (InterruptedException e) {
// Apanha a InterruptedException (outra forma de parar a thread)
System.out.println("[" + light.getId() + "] Traffic light thread interrupted.");
this.running = false; // Garante que o loop termina
}
System.out.println("[" + light.getId() + "] Traffic light thread stopped.");
}
/**
* Processes vehicles in the queue while the traffic light is GREEN.
* Logic extracted from IntersectionProcess.processGreenLight()
*
*/
private void processGreenLightQueue() throws InterruptedException {
//
while (running && light.getState() == TrafficLightState.GREEN && light.getQueueSize() > 0) {
Vehicle vehicle = light.removeVehicle(); //
if (vehicle != null) {
// 1. Get the crossing time (t_sem)
double crossingTime = getCrossingTimeForVehicle(vehicle); //
// 2. Simulate the time the vehicle takes to cross
Thread.sleep((long) (crossingTime * 1000)); //
// 3. Update vehicle statistics
vehicle.addCrossingTime(crossingTime); //
// 4. Update intersection statistics
process.getIntersection().incrementVehiclesSent(); //
// 5. Call the parent Process to send the vehicle
process.sendVehicleToNextDestination(vehicle); //
}
}
}
/**
* Gets the crossing time for a vehicle based on its type.
* Logic extracted from IntersectionProcess.getCrossingTimeForVehicle()
*
*
* @param vehicle The vehicle.
* @return The crossing time in seconds.
*/
private double getCrossingTimeForVehicle(Vehicle vehicle) {
switch (vehicle.getType()) { //
case BIKE:
return config.getBikeVehicleCrossingTime(); //
case LIGHT:
return config.getLightVehicleCrossingTime(); //
case HEAVY:
return config.getHeavyVehicleCrossingTime(); //
default:
return config.getLightVehicleCrossingTime(); //
}
}
/**
* Requests the thread to stop gracefully (graceful shutdown).
* Sets the 'running' flag to false. The thread will finish
* its current sleep cycle and exit the 'run()' loop.
*/
public void shutdown() {
this.running = false;
}
}