For the kind of thing you are doing you might think about a state-machine approach. A state-machine (or finite-state-machine) is a system with known states, and known transitions from one state to another when a particular event occurs. The application is defined in the definitions of the states, events, and transitions. The program itself simply looks for events, decides if they are relevant to the current state, and if so, transitions the system from the current state to the next state. This sounds quite complex and abstract but in fact is quite simple in reality. It is suitable for things where states can be defined, like traffic lights, lift mechanisms, etc. In my house I have numerous picaxe-based state machines running to control simple things like the doorbell and the solar panel pump, to complex things like the garage door, the central heating, and led lighting. There is a skeleton FSM program on my blog on this forum.
To get to your question, in the FSM world a delay is simply the definition of a future event. So delays are non-blocking, as the program continues to look for events that occur before the timer expires, and can deal with them independently, addressing the 'delay' when the next event is the expiry of the timer.
In my program, the event_monitor subroutine, which runs most of the time looking for all possible events, would see that an event is called for in x seconds time, and will count down the time each second, and when it reaches zero will generate the event for action. The action is simply the calling of the transition subroutine for the event.
Using this approach, you can have very complex activities with many states and events, but the code remains simple and understandable and thus maintainable. You might like to think about drawing up the logic of your railway system in the form of a state-transition diagram. There might be one for each train, running in parallel. The states for a train might be something like this:
Code:
[FONT=courier new]state (v next state) event transition action
stopped at platform x, loading departure time shut doors
v
stopped at platform x, waiting for green green signal start moving, then set signal to red
v
moving to signal a signal is green proceed and set signal to red(next state would be 'move to signal b' or whatever)
signal is red stop (next state would be 'stopped at signal a, waiting for green')
v
etc. and this has to be very thoroughly worked through, but this is true of any system to be programmed.[/FONT]
Apologies for the simplistic example, but the thing is, once you have the state/transition diagram debugged, programming is almost trivial.