You start only one process, initialized by the train/2 function. Your code is incomplete, so I can only guess, but I think that your code is wrong, because you have only one train process. For inspiration:
-module(trains). -export([startTrains/0]). startTrains() -> TotalDist = 100, Names = [trainA,trainB ], Self = self(), Trains = [spawn_link(fun() -> train(Name, Self) end) || Name <- Names], [ Train ! {start, Self, 0, TotalDist} || Train <- Trains], ok = collectResults(Names). collectResults([]) -> ok; collectResults(Trains) -> receive {stop, Name, Pos, Length} -> io:format("~p stops at ~p (~p)~n", [Name, Pos, Length]), collectResults(Trains -- [Name]); Msg -> io:format("Supervisor received unexpected message ~p~n", [Msg]), collectResults(Trains) after 10500 -> timeout end. train(Name, Sup) -> receive {start, Sup, Pos, Length} -> run_train(Name, Sup, Pos, Length); Msg -> io:format("~p received unexpected message ~p~n", [Name, Msg]), train(Name, Sup) end. run_train(Name, Sup, Pos, Length) when Pos < Length -> receive after 500 -> NewPos = Pos + 5, io:format("~p ~p~n", [Name, Pos]), run_train(Name, Sup, NewPos, Length) end; run_train(Name, Sup, Pos, Length) -> Sup ! {stop, Name, Pos, Length}.
But if I think seriously, I should look at the principles of gen_fsm and OTP. But at your current stage, keep playing with erlang primitives to make you feel better.