Estimate the value of PI using Monte Carlo method

I am struggling with an assigment here.

Case:
Write a program in C++ that estimates the value of Pi using the Monte Carlo method.

Make a class that does the estimation of Pi (EstimatePi, as i call it). The user determines how many times the Pi value is estimated (from the command line)

The main program will create instances of EstimatePi as child processes. Each instance estimates the value of pi, and saves it to a file. The parent process will wait for the child to finish after which it reads the contents of the child process, and prints the results.

The program should run like this from the terminal
 
 prog 10 10000000


The results from the calculation processes must be presented in the order in which they are completed. The
program should not wait for all calculation processes before the results presented

eg.

Process 6044 terminated normally with return value 0 PI: 3.141957
Process 6049 terminated normally with return value 0 PI: 3.140922
...
Process 6048 terminated normally with return value 0 PI: 3.141382
Process 6053 terminated normally with return value 0 PI: 3.141528
Average: 3.14147

My problem
My own output gives me the reverse i.e last process done comes first and my average pi which is supposed to be after the main program terminates, comes after the children

Here is my sample output from
 
Prog 5 100000


Estimating pi 5 processes with 100000 iterations for each process

Process #1 with pid: 20261 estimated pi: 3.141480
Process #2 with pid: 20297 estimated pi: 3.135920
Process #3 with pid: 20333 estimated pi: 3.134560
Process #4 with pid: 20371 estimated pi: 3.148080
Process #5 with pid: 20410 estimated pi: 3.150200
Average pi: 3.142048

Calculations took: 10.44 seconds
Process 20410 terminated normally with return value 0 PI: 3.150200
Process 20371 terminated normally with return value 0 PI: 3.148080
Process 20333 terminated normally with return value 0 PI: 3.182020
Process 20297 terminated normally with return value 0 PI: 3.135920
Process 20261 terminated normally with return value 0 PI: 3.244940
Press <RETURN> to close this window...


Code snippet from main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <vector>
#include <numeric>
#include <chrono>
#include <unistd.h>
#include <iomanip>
#include <sys/wait.h>
#include "EstimatePi.h"
#include "CommandLineHandler.h"
#include "Process.h"
#include <cstdint>

int main(int argc, char* argv[])
{
	const auto start = std::chrono::steady_clock::now();
	IntegerPair values{};
	double piValues{};
	double averagePi{};

	CommandLineHandler command(argc, argv); // Process commands and extract values

	if(command.isGoodParameters()){  // CommandLine values have been obtained
		 values = command.getValues();
		 int processes = values.first;
		 int iterations = values.second;

		 int wstatus;

		 // tell user what is happening..
		 std::cout << "Estimating pi " << processes << " processes with "
				   << iterations << " iterations for each process\n" << std::endl;

		 for(int i = 1; i <= processes; i++){
			pid_t cpid;
			double pi{};
			cpid = fork();
			if(cpid == -1){
				std::cerr << "Child creation unsuccessful" << std::endl;
			}
			if(cpid == 0){ /** Child process */
				EstimatePi estimate(iterations);
				pi = estimate.getPi();

				// Get this process and save the pid and pi values to file
				Process p(getpid(), pi);
				p.saveProcessToFile();

				// for debugging
				std::cout << "Process #" << i << " with pid: " << getpid()
						  << " estimated pi: " << std::setprecision(6)
						  << std::fixed<< pi << std::endl;

				piValues += pi;
				averagePi = piValues/i;

			}else{ /** Parent process*/
				pid_t wId;
				do{
					wId = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
					if(wId == -1){
						std::cerr << "A problem occured " << std::endl;
					}

					if (WIFEXITED(wstatus)) {
						Process p;
						p.readProcessFromFile(cpid);
						std::cout << "Process " << cpid
								  << " terminated normally with return value "
								  << wstatus << " PI: " << std::setprecision(6)
								  << std::fixed << p.getPi() << std::endl;

						// delete the file
						std::remove(std::to_string(cpid).c_str());

					}else if(WIFSIGNALED(wstatus)){
						std::cerr << "Process " << cpid << " killed by signal"
								  << WTERMSIG(wstatus) << std::endl;
					}
					else if(WIFSTOPPED(wstatus)){
						std::cerr << "Process " << cpid << " stopped by signal"
								  << WSTOPSIG(wstatus)<< std::endl;
					}else if(WIFCONTINUED(wstatus)){
						std::cerr << "Process " << cpid << " continuing..."
								 << std::endl;
					}
				}while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));

				exit(EXIT_SUCCESS);
			}
		 }
		 const auto end = std::chrono::steady_clock::now();
		 const auto diff = end - start;
		 std::cout << "Average pi: " <<  std::setprecision(6) << std::fixed
				   << averagePi << std::endl;

		 std::cout << "\nCalculations took: " << std::setprecision(2)
				   <<(std::chrono::duration<double, std::milli>(diff).count())/1000
				  << " seconds" << std::endl;
	}// END OF GOOD COMMANDLINE STUFF
	/*Bad command line stuff should have been printed already if that is the
	   case since they are printed with std::cerr*/

	return 0;
}



Thanks for your feedbacks
Last edited on
from your output
Process #1 with pid: 20261 estimated pi: 3.141480
...
Process 20261 terminated normally with return value 0 PI: 3.244940
¿why isn't the result the same?


Look at your process creation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for(int i = 1; i <= processes; i++){
	pid_t cpid;
	double pi{};
	cpid = fork();
	if(cpid == -1){
		std::cerr << "Child creation unsuccessful" << std::endl;
	}
	if(cpid == 0){ /** Child process */
		EstimatePi estimate(iterations);
		pi = estimate.getPi();
		//...
	}else{ /** Parent process*/
		pid_t wId;
		//...
			wId = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
		//...
		exit(EXIT_SUCCESS); // <---
	}
}
parent creates a child, waits for its termination and exits
child goes to the next iteration and becomes parent

instead of doing
p
|- c
|- c
|- c
|- c
|- c
you are doing
p
|- c
   |- c
      |- c
         |- c
            |- c


> my average pi which is supposed to be after the main program terminates
the last child is the one giving you the average.
Last edited on
Many thanks @ne555 for pointing that out.
I fixed it and the program now works as i had wished

The change i made was
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for(int i = 1; i <= processes; i++){
	pid_t cpid;
	double pi{};
	cpid = fork();
	if(cpid == -1){
		std::cerr << "Child creation unsuccessful" << std::endl;
	}
	if(cpid == 0){ /** Child process */
		EstimatePi estimate(iterations);
		pi = estimate.getPi();
		//...
         exit(EXIT_SUCCESS); // <--- this

	}else{ /** Parent process*/
		pid_t wId;
		//...
			wId = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
		//...
		
	}
}
Estimating pi using 5 processes with 100000 iterations for each process

Process #1 with pid: 1969 estimated pi: 3.133720
Process 1969 terminated normally with return value 0 PI: 3.133720

Process #2 with pid: 2010 estimated pi: 3.139680
Process 2010 terminated normally with return value 0 PI: 3.139680

Process #3 with pid: 2057 estimated pi: 3.146840
Process 2057 terminated normally with return value 0 PI: 3.146840

Process #4 with pid: 2144 estimated pi: 3.144120
Process 2144 terminated normally with return value 0 PI: 3.144120

Process #5 with pid: 2216 estimated pi: 3.141000
Process 2216 terminated normally with return value 0 PI: 3.141000

Average pi: 3.141072

Calculations took: 10.19 seconds
Press <RETURN> to close this window...


Thanks again for the review.
Topic archived. No new replies allowed.