import threading
class TrafficLight:
def __init__(self):
# 1 = North-South green, 0 = East-West green
self.green = 1
self.lock = threading.Lock()
def carArrived(
self,
carId: int, # ID of the car
direction: int, # 1: North, 2: East, 3: South, 4: West
turnGreen: 'Callable[[], None]', # Turn light green for this direction
crossCar: 'Callable[[], None]' # Car crosses the intersection
) -> None:
# North/South: direction 1 or 3, green == 1
# East/West: direction 2 or 4, green == 0
needGreen = 1 if direction in (1, 3) else 0
with self.lock:
if self.green != needGreen:
turnGreen()
self.green = needGreen
crossCar()
#include <mutex>
class TrafficLight {
private:
std::mutex mtx;
int green; // 1: North-South, 0: East-West
public:
TrafficLight() {
green = 1;
}
void carArrived(
int carId, // ID of the car
int direction, // 1: North, 2: East, 3: South, 4: West
function<void()> turnGreen,// Turn light green for this direction
function<void()> crossCar // Car crosses the intersection
) {
int needGreen = (direction == 1 || direction == 3) ? 1 : 0;
std::lock_guard<std::mutex> lock(mtx);
if (green != needGreen) {
turnGreen();
green = needGreen;
}
crossCar();
}
};
import java.util.concurrent.locks.ReentrantLock;
class TrafficLight {
private int green; // 1: North-South, 0: East-West
private final ReentrantLock lock;
public TrafficLight() {
green = 1;
lock = new ReentrantLock();
}
public void carArrived(
int carId, // ID of the car
int direction, // 1: North, 2: East, 3: South, 4: West
Runnable turnGreen, // Turn light green for this direction
Runnable crossCar // Car crosses the intersection
) {
int needGreen = (direction == 1 || direction == 3) ? 1 : 0;
lock.lock();
try {
if (green != needGreen) {
turnGreen.run();
green = needGreen;
}
crossCar.run();
} finally {
lock.unlock();
}
}
}
class TrafficLight {
constructor() {
// 1 = North-South green, 0 = East-West green
this.green = 1;
this.lock = Promise.resolve();
}
carArrived(carId, direction, turnGreen, crossCar) {
const needGreen = (direction === 1 || direction === 3) ? 1 : 0;
this.lock = this.lock.then(() => {
if (this.green !== needGreen) {
turnGreen();
this.green = needGreen;
}
crossCar();
});
return this.lock;
}
}
The Traffic Light Controlled Intersection problem simulates a four-way intersection controlled by a traffic light. The intersection allows cars to approach from four directions: North (1
), East (2
), South (3
), and West (4
).
The intersection's traffic light can be green for either the North-South or East-West direction at any one time, but not both. Cars arrive at the intersection and must wait if the light is not green for their direction. When it is their turn, they can either change the light (if needed) and then cross.
You are to implement a class with a method carArrived
that will be called for each car. The method receives:
carId
: The unique ID of the cardirection
: The direction the car comes from (1=North, 2=East, 3=South, 4=West)turnGreen
: A function to turn the light green for this car's directioncrossCar
: A function to let the car cross the intersectionKey constraints:
The core challenge is to synchronize cars arriving from different directions so that only cars facing a green light can cross. Since the intersection is shared, we need to prevent race conditions where two cars might try to change the light at the same time, or cross when the light is not green for their direction.
The brute-force approach would be to let each car check the light and change it if needed, but without synchronization this can cause problems if two cars from different directions act at the same time. Therefore, we need some form of locking or mutual exclusion to ensure that checking and changing the light is atomic (cannot be interrupted).
The optimization is to use a lock (mutex) to ensure only one car can check and change the light at a time. This prevents inconsistent states and ensures correct order of operations. We also minimize unnecessary light switches by checking if the light is already green before switching.
Let's break down the steps to implement the solution:
green
) to indicate which direction currently has the green light. For simplicity, use 1
for North-South and 0
for East-West.direction
1 or 3) or East-West green (direction
2 or 4).turnGreen()
and update the state variable.crossCar()
to let the car cross the intersection.This approach ensures that all operations are thread-safe, cars only cross when the light is green for their direction, and unnecessary light switches are avoided.
Let's consider a scenario with four cars arriving in this order:
direction = 1
)direction = 2
)direction = 3
)direction = 4
)Step-by-step:
turnGreen()
to switch the light, then crosses.turnGreen()
to switch the light back, then crosses.turnGreen()
to switch the light, then crosses.At each step, the lock ensures that only one car can make decisions about the light and cross at a time, preventing conflicts.
Brute-force approach:
carArrived
acquires the lock, checks the light, possibly switches it, and lets the car cross. All these are O(1) operations.The Traffic Light Controlled Intersection problem is about safe concurrent simulation of cars at a four-way intersection. The key insight is to use a lock to synchronize state changes, ensuring that only one car at a time can check and change the light and cross. This prevents race conditions and ensures that cars only cross when the light is green for their direction, and the light is only switched when necessary. The solution is elegant because it is both simple (O(1) per operation) and robust to concurrency, using minimal state and synchronization.