goto isn't that dangerous, or that strange. It has it's place (like inline retries instead of recursion or for-loops) but it's rare to reach for them in most languages.
Semaphores are like a restricted form of goto which lets you branch exactly, say, two lines forward or two lines back. Building concurrency primitives out of semaphores is like using that goto to build control flow.