I am trying to Monte Carlo simulate an approximation of pi, by placing random points in a unit square, and seeing which points fall inside the unit circle. I am asked to do this with threads using pthreads
. I am familiar with CUDA programming to some extent, so I am a bit familiar with some of the pitfalls. I seem to have a working program that runs faster than the sequential single-threaded program. However, I have two questions, that I believe pertains to my understanding of parallelizing the code.
- At first I passed a single pointer to the variable
int* ptsInCircle
to both threads. I had a slight suspicion that this might not work, since both threads try to simultaneously write to the same block of memory. It did not work at all, and I had to implement it as below, using two separate pointers, and join the results at the end. Can someone explain to me why this is the case? I am not sure I understand. One thing I did notice, was that if I printed the value of ptsInCircle within a loop, it seemed as though the variable was correctly updated. Is this due to each thread having to spend more time each iteration, allowing the other thread to access the address without conflicting with each other? - I seem to, even using
int numOfPts = 1e8
as an argument to the function, have slight oscillations of the value between concurrent executions of the binary. Why is this? - Also any tips and points on the structure of my program, or parallelizing this case in particular are greatly appreciated. Thanks in advance.
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include "piApproxMultithreaded.h"
typedef struct placePtsArgStruct {
unsigned int* seed;
double startingPt;
double numOfPts;
int* ptsInCircle;
double unitCircleRadius;
} placePtsArgStruct;
double randomNumber( unsigned int *seed ){
/*_Thread_local*/
double maxRand = (double)RAND_MAX; // Maximum random number, cast to double
double randNum = (double)rand_r( seed ); // Generate pseudo-random number from seed, cast to double
return 2 * randNum/maxRand - 1; // Recast number between -1 and 1
}
void* placePts( void* placePtsArgStructInput ){
placePtsArgStruct* args = ( placePtsArgStruct* )placePtsArgStructInput;
unsigned int* seed = args->seed ;
double startingPt = args->startingPt ;
double numOfPts = args->numOfPts ;
int* ptsInCircle = args->ptsInCircle ;
double unitCircleRadius = args->unitCircleRadius ;
double xpos = 0;
double ypos = 0;
for ( int iteration = startingPt; iteration < numOfPts; iteration++ ){
xpos = randomNumber(seed);
ypos = randomNumber(seed);
if ( sqrt( pow(xpos, 2) + pow(ypos, 2) ) <= unitCircleRadius ){
(*ptsInCircle)++;
//printf("%d\n", *ptsInCircle);
}
}
return NULL;
}
void piApproxMultithreaded( int numOfPts ){
unsigned int seed = time(NULL) ;
double unitCircleRadius = 1.0 ;
int* ptsInCircle_first = malloc(sizeof(int));
*ptsInCircle_first = 0;
int* ptsInCircle_second = malloc(sizeof(int));
*ptsInCircle_second = 0;
int startingPt_firstPart = 0;
int startingPt_secondPart = (int)(((double)numOfPts)/2.0);
int numOfPts_firstPart = startingPt_secondPart;
int numOfPts_secondPart = numOfPts;
placePtsArgStruct placePtsArgStruct_firstPart = { &seed, startingPt_firstPart , numOfPts_firstPart , ptsInCircle_first, unitCircleRadius };
placePtsArgStruct placePtsArgStruct_secondPart = { &seed, startingPt_secondPart, numOfPts_secondPart, ptsInCircle_second, unitCircleRadius };
pthread_t firstPart;
pthread_t secondPart;
pthread_attr_t* attributes = NULL;
pthread_create( &firstPart, attributes, placePts, (void*)&placePtsArgStruct_firstPart );
pthread_create( &secondPart, attributes, placePts, (void*)&placePtsArgStruct_secondPart );
void* status = NULL;
pthread_join(firstPart, status);
pthread_join(secondPart, status);
double ptsInCircle = *ptsInCircle_first + *ptsInCircle_second;
double myPiApprox = 4.0*ptsInCircle/((double)numOfPts);
printf("My approximation of pi = %g\n" , myPiApprox );
printf("Pi is actually = %g\n" , M_PI );
printf("Deviation is %g percent\n" , fabs(1.0-myPiApprox/M_PI)*100 );
}
I am of course calling the program from a seperate file main.c
:
#include "piApproxMultithreaded.h"
#include <pthread.h>
int main( void ){
int numOfPts = 1e9;
piApproxMultithreaded( numOfPts );
return 0;
}
Lastly, I have the header file piApproxMultithreaded.h
#ifndef HAVE_PIAPPROX_H
#define HAVE_PIAPPROX_H
#include <pthread.h>
void piApproxMultithreaded( int numOfPts );
#endif
Aucun commentaire:
Enregistrer un commentaire