Factorize All Numbers Up to a Given Number this post is sort of a continuation of my answer on the following question: Fast Algorithm to Factorize All Numbers Up to a Given Number. As this post explains - We need to factorize all the numbers up to a large N.
At first I gave a python solution which was pretty slow (since - you know, python), than I decided to write it in C++. I am not that good with C++ and I would like to have a code review about that answer:
#include &lt;math.h&gt;
#include &lt;unistd.h&gt;
#include &lt;list&gt;
#include &lt;vector&gt;
#include &lt;ctime&gt;
#include &lt;thread&gt;
#include &lt;iostream&gt;
#include &lt;atomic&gt;

#ifndef MAX
#define MAX 200000000
#define TIME 10
#endif


std::atomic&lt;bool&gt; exit_thread_flag{false};

void timer(int *i_ptr) {
    for (int i = 1; !exit_thread_flag; i++) {
        sleep(TIME);
        if (exit_thread_flag) {
            break;
        }
        std::cout &lt;&lt; &quot;i = &quot; &lt;&lt; *i_ptr &lt;&lt; std::endl;
        std::cout &lt;&lt; &quot;Time elapsed since start: &quot; 
                  &lt;&lt; i * TIME 
                  &lt;&lt; &quot; Seconds&quot; &lt;&lt; std::endl;
    }
}

int main(int argc, char const *argv[])
{
    int i, upper_bound, j;
    std::time_t start_time;
    std::thread timer_thread;
    std::vector&lt; std::list&lt; int &gt; &gt; factors;

    std::cout &lt;&lt; &quot;Initiallizating&quot; &lt;&lt; std::endl;
    start_time = std::time(nullptr);
    timer_thread = std::thread(timer, &amp;i);
    factors.resize(MAX);
    std::cout &lt;&lt; &quot;Initiallization took &quot; 
              &lt;&lt; std::time(nullptr) - start_time 
              &lt;&lt; &quot; Seconds&quot; &lt;&lt; std::endl;

    std::cout &lt;&lt; &quot;Starting calculation&quot; &lt;&lt; std::endl;
    start_time = std::time(nullptr);
    upper_bound = sqrt(MAX) + 1;
    for (i = 2; i &lt; upper_bound; ++i)
    {
        if (factors[i].empty())
        {
            for (j = i * 2; j &lt; MAX; j += i)
            {
                factors[j].push_back(i);
            }
        }
    }
    std::cout &lt;&lt; &quot;Calculation took &quot; 
              &lt;&lt; std::time(nullptr) - start_time 
              &lt;&lt; &quot; Seconds&quot; &lt;&lt; std::endl;

    // Closing timer thread
    exit_thread_flag = true;

    std::cout &lt;&lt; &quot;Validating results&quot; &lt;&lt; std::endl;
    for (i = 2; i &lt; 20; ++i)
    {
        std::cout &lt;&lt; i &lt;&lt; &quot;: &quot;;
        if (factors[i].empty()) {
            std::cout &lt;&lt; &quot;Is prime&quot;;
        } else {
            for (int v : factors[i]) {
                std::cout &lt;&lt; v &lt;&lt; &quot;, &quot;;
            }
        }
        std::cout &lt;&lt; std::endl;
    }
    
    timer_thread.join();
    return 0;
}

I would especially like a review about my usage of threads (I am afraid it might slow down the code). The performance are reaching 6619 which is the 855th (out of 1662 primes up to 14140 ~ square root of 200000000) in 1.386111 hours, if you find any way to make it faster I will be amazing! A more semantic review is also very welcome (Like #include order?).
Just for fun and a point of reference if you are trying to run the code yourself:

Where X is time and Y is the prime reached (i). The orange tradeline is y = 13 * 1.00124982852632 ^ x. The graph is exponential since indeed the inner loop time is getting shorter.
The orange tradeline says I will reach 14107 (The highest prime before the square root) at x ≈ 5595.842803197861 seconds which is 1.554 hours!
Timing
The timer thread is unnecessary and an inaccurate way to measure time.

I do now know about this system_clock, system calls might slow down the process (maybe the context switch even more though)

Querying the time costs a bit of time, even if it does not involve an actual system call - which it really may not, there are lots of clever tricks for example clock_gettime uses vDSO on modern Linux and reads from a shared memory location and QueryPerformanceCounter reads the TSC on typical Windows systems, there is no transition into and out of kernel mode. It's never a lot of time relative to what this program is doing, the overhead of getting the time is only an issue when timing very short spans of time. Even if getting the time costs a milisecond (which would be unacceptable and considered a bug in the implementation), it would still be OK for this program.
Performance
Storing the factors in explicit linked lists is a major performance problem, and unlike usual, using vectors wouldn't be great either. There is an alternative: store only one factor of a number. That still gives a complete factorization for any number, because if a number N has a factor factors[N], then you can divide N by that factor and look up a factor of the new (smaller) number and so on, until 1 is reached.
That way the inner loop of the sieve only does a bunch of stores into a vector, nothing heavy-weight like dynamically allocating nodes of a linked list, and the memory usage does not get out hand.
As a convention, I'll use that the lowest factor of a prime is the prime itself. That is the mathematical definition, and it makes iterating over the implicit factor lists easy.
Other
Defining MAX by macro definition and putting local variable declarations at the top of the function are very C things to do. Even C has moved away from &quot;all locals at the top&quot;. As general guidelines, I recommend using const variables instead of defines, and limiting local variables with the smallest possible scope. That does not repeatedly incur a cost for &quot;making a variable&quot; because that's not how that happens, any fixed space a function needs is allocated all at once at function entry. Besides, most local variables spend their entire lifetime in registers.
Avoid #include &lt;unistd.h&gt; if possible/reasonable, it does not exist on all platforms.
Pick a brace style and stick to it. There were &quot;same line&quot;-braces and &quot;next line&quot;-braces. There are various opinions on which should be used, but at least they shouldn't be mixed.
In total, the code might come out like this:
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;math.h&gt;
#include &lt;chrono&gt;

int main() {
    const int MAX = 200000000;
    std::vector&lt;int&gt; factors;

    std::cout &lt;&lt; &quot;Initiallizating&quot; &lt;&lt; std::endl;
    auto start_time = std::chrono::steady_clock::now();
    factors.resize(MAX);
    std::cout &lt;&lt; &quot;Initiallization took &quot;
        &lt;&lt; std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::steady_clock::now() - start_time).count()
        &lt;&lt; &quot; ms&quot; &lt;&lt; std::endl;

    std::cout &lt;&lt; &quot;Starting calculation&quot; &lt;&lt; std::endl;
    start_time = std::chrono::steady_clock::now();
    int upper_bound = sqrt(MAX) + 1;
    for (int i = 2; i &lt; upper_bound; ++i) {
        if (factors[i] == 0) {
            for (int j = i; j &lt; MAX; j += i) {
                factors[j] = i;
            }
        }
    }
    std::cout &lt;&lt; &quot;Calculation took &quot;
        &lt;&lt; std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::steady_clock::now() - start_time).count()
        &lt;&lt; &quot; ms&quot; &lt;&lt; std::endl;

    std::cout &lt;&lt; &quot;Validating results&quot; &lt;&lt; std::endl;
    for (int i = 2; i &lt; 20; ++i) {
        std::cout &lt;&lt; i &lt;&lt; &quot;: &quot;;
        if (factors[i] == i) {
            std::cout &lt;&lt; &quot;Is prime&quot;;
        }
        else {
            for (int N = i; N &gt; 1; N /= factors[N]) {
                std::cout &lt;&lt; factors[N] &lt;&lt; &quot;, &quot;;
            }
        }
        std::cout &lt;&lt; std::endl;
    }

    return 0;
}

On my PC the sieving takes about 2.5 seconds now. Ideone is a bit slower but the program is fast enough to run there too.