One important point - when you're using eg. DirectX, you really, really don't care about the main thread. Let it be as free as possible, it doesn't do anything. All the inputs and outputs are processed separately from the UI thread, so why tie them to it? That's only going your window to stop responding if your rendering / updating is too busy. Also, yes, multithreading is complicated. But that's not the case here - you don't want your threads to interact, so everything is fine - they don't access each other's resources, and they don't need to communicate save for a quit message :)
Let's explore Windows + DirectX more:
You usually want a fairly predictable update (/frame) rate. But at the same time, you want to process windows messages (that's the things like "move the window", "resize the window", "press Alt-F4"). Now, you want to process an incoming windows message as soon as possible. Why? Because they contain important things, like
WM_QUIT. And Windows will report your application as "not responding" if you, well, don't respond to the windows messages.
Another important thing is that when you use
SendMessage to send a windows message, you're blocking the sender, until you actually read the message. If you have WM processing tied to your game loop, this can mean many issues (since the update loop will usually take a lot of time to go through, say 16ms for a 60 FPS game, while WM processing is usually very much under-ms). If someone eg. sends key presses to your application (like some macro program), there's a big difference between receiving 100 WM_CHAR messages in a row and taking 16 ms to process each one.
All that said, this is incredibly platform dependent. On Windows with DirectX, I'd advise to really separate the WM processing from the game itself. The only cases where you actually want them to be tied are those like "I want to resize the game window". Different platforms have different best behaviours and different constraints.