I posted on cplusplus but decided to put here for better response. Idea is to create race condition, done in C. main() will fire of two threads (can be changed to arbitrary by setting CONFIG_THREAD_COUNT). Each thread will run hello() in which it loops X thousands of times to read SUM variable wrote to file, add RAND() to SUM and write the RAND() as well as SUM+RAND() to file. Therefore each thread's loop will create thousands of file in current directory: file-<threadID>-<loopNo> which I merge into single file "cat file-* > file.all.log.
Instead of scouring through thousands of lines for error, race-check.py little utility will read the merged file one-by-one, parse and do the addition again and compare the result. (code below).
If I may see result looks promising:
With mutex line disabled, expected the possibility of race condition. with 2 threads and 20,000 loops, python found two addition that makes no sense:
Code:
[root@dev]# cat race.found.log
RACE!: ['75330', '2', '75877']
RACE!: ['103486', '2', '104581']
RACE!: ['34712', '3', '35232']
RACE!: ['105220', '5', '105751']
checked the surrounding line with addition 75530+2
Quote:
[root@dev]# egrep -ir "75330:2" file.all.log -A 2 -B 2
threadNo. 0:75321:4:75325
threadNo. 0:75325:5:75330
threadNo. 0:75330:2:75877
threadNo. 0:75877:2:75879
threadNo. 0:75879:4:75883
I then reduced the CONFIG_THREAD_COUNT to 1 effectively making a single-threaded or no concurrency, main() will launch only 1 thread and do not bother with SUM, therefore only only one instance of hello() will sequentially add it thousands of times and yes, with the result, race-check.py did not find any inconsistency.
As a next step, I am applying the mutex inside the hello and see how it goes which I haven't tried.
Code:
#include <list>
#include <mutex>
#include <algorithm>
#include <thread>
#include <iostream>
#include <fstream>
#include <sstream>
#include <unistd.h>
using namespace std;
std::mutex mutex_sum;
int sum = 0;
void hello(int pId, int pStat[])
{
int pNum;
int i;
std::cout << pId << ": Hello CONCURRENT WORLD " << endl;
for (int i = 0; i < 1000000; i++ ) {
pNum = rand() % 4 + 2;
cout << pId << ": " << ", loop: " << i << endl;
// read + sum + read and write to file.
ofstream myfile;
ostringstream oss;
oss << "file-" << pId << "-" << i;
myfile.open(oss.str());
myfile << "threadNo. " << pId << ":" << sum;
sum += pNum;
myfile << ":" << pNum << ":" << sum << endl;
pStat[pId] = 1;
myfile.close();
}
std::cout << pId << ": Done sleeping exiting now..." << endl;
}
int main()
{
// Declare, initialize variables.
int i;
const int CONFIG_THREAD_COUNT = 2;
int stat[CONFIG_THREAD_COUNT];
int sum = 0;
// launch threads.
for ( i = 0; i < CONFIG_THREAD_COUNT; i ++ ) {
stat[i] = 0;
std::thread t(hello, i, stat);
t.detach();
}
cout << "Checking thread status-s..." << endl;
while (sum != CONFIG_THREAD_COUNT) {
sum = 0;
for (i = 0; i < CONFIG_THREAD_COUNT; i++) {
cout << stat[i] << ", ";
sum += stat[i];
}
cout << "main(): sum: " << sum << ". waiting for all threads to finish..." << endl;
usleep(2 * 1000000);
}
return 0;
}
race-check.py:
Code:
fp = open("file.all.log")
fpOut = open("race.found.log", 'w')
if not fp:
print "Failed to open."
line = fp.readline().strip()
counter = 0
while line:
print line
operands= line.split(":")[1:4]
print "operands: ", operands
if int(operands[0]) + int(operands[1]) != int(operands[2]):
fpOut.write("RACE!: " + str(operands) + "\n")
counter += 1
line = fp.readline().strip()
if counter == 0:
fpOut.write("No race condition found.")
print "No race condition found."
else:
print "At least one race condition found: ", counter
fp.close()
fpOut.close()