Você está executando cada comando sequencialmente. No momento em que o script chegar a sem --wait , todos os três comandos foram executados e finalizados.
Tente adicionar um & à linha sem -j 3 $cmd . Isso executará cada comando em segundo plano, em paralelo.
cmds=("prog 1 2 3" "prog 4 5 6" "prog 7 8 9")
for cmd in "${cmds[@]}"
do
sem -j 3 $cmd &
done
sem --wait