There's no timeline for multithreading. As far as I can tell from conversations and forum threads about this, it would be difficult or impossible to do at all in a large sense. There's more hope for targeted improvements, but that still has the problem of me not knowing a thing about it or where best to apply it, and the risk of a months-long delay with zero gain on the other end.
One thing to keep in mind is that there are multiple approaches to concurrency and/or parallelism, and they can have
exceedingly different tradeoffs.
In particular, the ones I see as most likely to be useful:
1.) OpenMP
OpenMP is a framework designed to allow adding parallelism with
minimal changes, while keeping the code entirely capable of compiling in single-threaded mode. It works by way of adding special #pragma directives immediately before the code that needs to behave in interesting ways in a parallel setting. Likely the most useful to you are:
"#pragma omp parallel for" - instructs the compiler to try and parallelize what it can of the for loop that follows the directive
"#pragma omp critical" - instructs the compiler that the following block or function is a 'critical section' that must execute in only one thread at a time
"#pragma omp master" - similar to critical, but must execute only in the main thread
OpenMP is supported in GCC and can be enabled via the -fopenmp compiler directive, and
in Visual Studio 2010 and newer (though only OpenMP 2.0) with the /openmp directive.
2.) Speculative computation
It may be possible to predict _partial_ information early, and then speculatively compute results for each possible value the unknown information could take. This could be of value for any function that either does not modify state itself and merely calculates what modifications would be, or is an input to a later conditional. The results could then be stored in a map from the inputs to the output value, saving later computation if the prediction is correct. This is very much a time-memory tradeoff, and would need parameters to decide how much CPU and memory to spend on it.
I suspect a big place this might help is temperature and water level fluctuations - if a cell usually fluctuates between two values, and the parameters are relatively predictable, this could drastically reduce the main-thread's CPU load for such things: Once all the parameters are known, it just looks up the appropriate value.
This is a special case of memoization, in which the function is called speculatively to aggressively memoize values not yet encountered.
Memoization itself might be a useful trick as well, though it doesn't make use of threading. However, memoization-based techniques only work if all inputs to a function are known/declared/factored into the key of the map.
3.) Independent calculations that synchronize on tick
I suspect there are some _kinds_ of calculations that rarely or never interact with each other before the next tick. Running these in threads and then synchronizing on a semaphore at the end of a tick could be a relatively low-impact change.