Created
February 13, 2018 09:05
-
-
Save SakiiR/66dab8fb11dde7a62c0aa9d38a6dfdf8 to your computer and use it in GitHub Desktop.
Threads / Mutex -> Monte-Carlo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Monte Carlo - Threads exercise | |
* | |
* Compile with: gcc ./mcarlo.c -o mcarlo -lpthread -lm | |
*/ | |
#include <unistd.h> | |
#include <time.h> | |
#include <math.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#define RETURN_SUCCESS (0) | |
#define RETURN_FAILURE (1) | |
#define THREAD_SUCCESS (RETURN_SUCCESS) | |
#define THREAD_FAILURE (RETURN_FAILURE) | |
#define SYSCALL_FAILURE (-1) | |
#define PROGRESS (1) | |
#define WORKER_COUNT (10) | |
#define WITHIN_CIRCLE(x, y) (sqrt(x*x + y*y) < 1) | |
#define RANDOM_DOUBLE ((random() / ((double)RAND_MAX + 1)) * 2.0 - 1.0) | |
#define PI(a, b) ((double)(4.0 * ((double)b / (double)a))) | |
typedef struct s_mcarlo | |
{ | |
unsigned long long p_todo; | |
unsigned long long p_count; | |
unsigned long long p_within_circle; | |
double pi; | |
} t_mcarlo; | |
typedef struct s_thread | |
{ | |
pthread_t thread_id; | |
pthread_attr_t thread_attr; | |
unsigned long long points_computed; | |
int status; | |
} t_thread; | |
void *worker(void *arg); | |
t_mcarlo mcarlo = {0, 0, 0, 0.0}; | |
pthread_mutex_t lock; | |
int main(int argc, char **argv) | |
{ | |
t_thread threads[WORKER_COUNT]; | |
unsigned int i = 0; | |
unsigned long long point_number = 0; | |
/* Checking command line parameters */ | |
if (argc < 2) | |
{ | |
fprintf(stderr, "[^] USAGE: ./mcarlo <point_number>\n"); | |
return RETURN_FAILURE; | |
} | |
/* Converting the char* argv[1] into long long */ | |
if ((point_number = atoll(argv[1])) < 1) | |
{ | |
fprintf(stderr, "[-] point_number should be >= 1\n"); | |
return RETURN_FAILURE; | |
} | |
/* Initializing mutex */ | |
if (pthread_mutex_init(&lock, NULL) != 0) | |
{ | |
printf("[-] Failed to init mutex !\n"); | |
return RETURN_FAILURE; | |
} | |
/* Setting the random seed to the currant time in second */ | |
srand(time(NULL)); | |
/* Number of points to compute stored in the working structure */ | |
mcarlo.p_todo = point_number; | |
/* Initializing threads, then, start them */ | |
printf("[~] Launching %d threads ..\n", WORKER_COUNT); | |
for (i = 0 ; i < WORKER_COUNT ; ++i) | |
{ | |
/* By default, the thread succeed */ | |
threads[i].status = THREAD_SUCCESS; | |
/* Setting default thread attr */ | |
pthread_attr_init(&threads[i].thread_attr); | |
/* Starting threads */ | |
if (pthread_create(&threads[i].thread_id, &threads[i].thread_attr, worker, &mcarlo) != RETURN_SUCCESS) | |
{ | |
fprintf(stderr, "[-] Failed to start thread %d\n", i); | |
threads[i].status = THREAD_FAILURE; /* Set the thread creation status to know if we have to join() it */ | |
} | |
} | |
/* Waiting for the threads to finish */ | |
for (i = 0 ; i < WORKER_COUNT ; ++i) | |
{ | |
unsigned long long *p; | |
/* Waiting for thread i to finish */ | |
pthread_join(threads[i].thread_id, (void**)&p); | |
if (p != NULL) /* If worker malloc doesn't failed */ | |
{ | |
threads[i].points_computed = *p; | |
printf("[~] Thread %d computed %llu points\n", i + 1, threads[i].points_computed); | |
} | |
free(p); | |
} | |
printf("[+] All Threads finished ! %llu/%llu PI = %f\n", mcarlo.p_within_circle, mcarlo.p_count, PI(mcarlo.p_count, mcarlo.p_within_circle)); | |
pthread_mutex_destroy(&lock); | |
return RETURN_SUCCESS; | |
} | |
void *worker(void *arg) | |
{ | |
/* Casting the void* pointer to retrieve our t_mcarlo structure */ | |
t_mcarlo *mcarlo = (t_mcarlo *)arg; | |
double x = 0, y = 0; | |
unsigned long long *points_computed; | |
if ((points_computed = malloc(sizeof(unsigned long long) * 1)) == NULL) | |
return NULL; | |
while (mcarlo->p_count < mcarlo->p_todo) | |
{ | |
/* Creating random values (x, y coordinates) */ | |
x = RANDOM_DOUBLE; | |
y = RANDOM_DOUBLE; | |
/* Locking the mutex, accessing shared memory */ | |
pthread_mutex_lock(&lock); | |
/* Increasing number of computed points */ | |
if (++mcarlo->p_count && WITHIN_CIRCLE(x, y)) /* Check is the coordinates are within the circle */ | |
++mcarlo->p_within_circle; | |
/* Inc the computed points count to determine how many points a thread has computed */ | |
++*points_computed; | |
/* Unlocking the mutex, not using shared memory anymore */ | |
pthread_mutex_unlock(&lock); | |
/* Logging some info 10 times if we are in debug/progress mode */ | |
if (PROGRESS && mcarlo->p_count % (mcarlo->p_todo / 10) == 0) | |
printf("Progress: %llu/%llu -> %f\n", mcarlo->p_within_circle, mcarlo->p_count, PI(mcarlo->p_count, mcarlo->p_within_circle)); | |
} | |
/* Exiting at the end of the job */ | |
//pthread_exit(points_computed); | |
return (void *)points_computed; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment