#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;
}