When I have been faced with a similar issue, I have generally chosen the 2nd architecture. We have a large C++ library of methods for scientific computations, some of which can take time and need to communicate status back to the controller so it can post a progress bar, allow for aborting the operation, etc. This library is used in Qt apps, MFC apps, and headless apps on embedded linux systems so it is vanilla C++.
In most cases, the computation (simulation, in your case) has a set of well-defined callbacks for which the controller can supply pointers to callback functions. At appropriate points in the simulation loop, the simulation will invoke the callback if a pointer has been supplied.
To interface this to the Qt world, I construct a Facade which maps the callbacks into Qt signals and translates C++ types into Qt types (e.g. std::wstring -> QString) if desired. Translation gives the option of using simulation-specific objects to talk to the facade class, but these can be hidden behind the "facade" (hence the name of the design pattern). The facade class could be a GUI, or simply be a QObject for use by other Qt objects. This gives some ability to disconnect the Qt world from the simulation world - the Qt class could have a "stop" button that simply sets a flag in the facade class. Next time the simulation asks, "OK to keep going?", the facade supplies the value of the flag.
Note that in the main application, unless you put the simulation into its own thread, you will still have to service the event loop (i.e. call processEvents()) in order to keep the GUI "live". The facade class can do this for you by calling processEvents() in each callback function, but unless the callback is invoked frequently, the GUI will be doggy.
Bookmarks