------------------------------------------------------------------------------
MC logo
Synchronization Error
[^] Process and Thread Synchronization
------------------------------------------------------------------------------
badcount.cpp
#include <iostream>
#include <cstdlib>
#include <list>
#include <thread>
#include <mutex>

using namespace std;

// This is a global counter.
int global_counter = 0;

// This is a thread which simply increments the global counter a bunch of
// times without locking it.  That's a bad idea.
void bad_incrementer(int num)
{
        while(num--) ++global_counter;
}

// This is a mutex to synchronize increments on the global counter so it can
// be incremented correctly.
mutex counter_lock;

// This increments the global counter the indicated number of times, but
// locks the mutex each time so the increment will be correct.
void good_incrementer(int num)
{
        while(num--) {
                counter_lock.lock();
                ++global_counter;
                counter_lock.unlock();
        }
}

// Get an integer from the command line, with default
int getint(int &argc, char ** &argv, int dflt)
{
        if(argc > 0) {
                dflt = atoi(argv[0]);
                --argc; ++argv;
        }

        return dflt;
}

// This main program is run with parameters [ protect ] nthread and niter, 
// which will start nthread threads running, each making niter iterations, 
// wait them, then see how many increments were lost.  If the protect word
// is given, the threads will synchronize increments, otherwise they don't.
int main(int argc, char **argv)
{
        // Get rid of program name.
        --argc; ++argv;

        // Collect the arguments.
        bool protect = false;
        if(argc > 0 && argv[0] == string("protect")) {
                protect = true;
                --argc; ++argv;
        }
        int nthread = getint(argc, argv, 10);
        int niter = getint(argc, argv, 10);

        // Create the threads.
        list<thread> threads;
        for(int n = 0; n < nthread; ++n) {
                if(protect)
                        threads.push_back(thread(good_incrementer, niter));
                else
                        threads.push_back(thread(bad_incrementer, niter));
        }

        // Join the threads.
        for(thread &t: threads) t.join();

        // Report the results.
        int nincr = nthread*niter;
        cout << "Global counter is " << global_counter <<
                ", was incremented " << nincr << " times.  ";
        if(global_counter < nincr)
                cout << nincr - global_counter << " lost increments ("
                     << 100.0*(nincr - global_counter)/nincr << "%." << endl;
        else
                cout << "No lost increments." << endl;
}