Skip to content
Extraits de code Groupes Projets
fact.c 8,49 Kio
//
// Modified on 09/05/2020.
//
#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
//#include <time.h>
#include <pthread.h>

/* STRUCTURES AND VARIABLES */

/* "struct factorization"
 * "prime_dividers" is an array containing max N dividers
 * "cnt" is the number of calculated dividers
 * "number" is number to calculate the prime dividers
*/
#define N 10  // Max number of dividers in the buffer

typedef struct factorization {
    unsigned long prime_dividers[N];
    unsigned int cnt;
    unsigned long number;
} factor;

/* struct file_descriptors
 * "in" is the inputfile file descriptor
 * "out" is the outputfile file descriptor
 * "options" "v" (verbose) with debugging information, "q" without debugging information
 */
typedef struct file_descriptors {
    FILE *in;
    FILE *out;
//    char options; // For internal command test
} fd;
// Declare f (type fd). Structure containing the file descriptors
fd f;

/* MUTEX  */
pthread_mutex_t mutex_readwrite; // define mutex variable

/*
* FUNCTIONS used in the programme:
* bool is_div(unsigned long, unsigned long);
* bool is_prime(unsigned long);
* factor *prime_divs(unsigned long);
* void *read_write(fd);
*/
bool is_div(unsigned long numbr, unsigned long i){
    if((numbr % i) == 0) {  // verify if i is the divider of numbr
        return(true);       // i is a divider of numbr
    } else {
        return(false);      // i is not a divider of numbr
    }
}


bool is_prime(unsigned long nbr) {
    /*
 * Optimised solution with less loop, see: https://fr.wikipedia.org/wiki/Nombre_premier
 * "Crible d'Ératosthène:
 * Les premiers algorithmes pour décider si un nombre est premier
 * (appelés tests de primalité) consistent à essayer de le diviser par tous les nombres
 *  qui n'excèdent pas sa racine carrée"
 */
    unsigned long j;
    for (j = 2; j <= sqrt(nbr); j++) {
        if ((nbr % j) == 0) {       // verify if i is the divider of nbr
            return (false);         // i is a divider of nbr
        }
    }
    return (true); // i is a prime number
}


factor* prime_divs (unsigned long numbr) {
    factor *dividers; // Structure storing dividers and their number
    /* Allocation of memory for "struct factor" and
     * initialization the "dividers" struture to zero
     * */
    dividers = (factor *) calloc(1, sizeof(factor));
    unsigned int n = 0;
    dividers->number = numbr;
    unsigned long tmp_number = dividers->number;
    unsigned long i;
    for(i = 2; i <= tmp_number ; i++) {
        if(is_div(dividers->number,i) == true){
            if(is_prime(i) == true){
                dividers->prime_dividers[n] = i;
                /* The max numbers of loops is reduced
                 * from "number" to "tmp_number/i"
                 * */
                tmp_number = tmp_number/i;
                if(i != dividers->number) {
                    n++;
                }
            }
        }
    }
    dividers->cnt = n;
    return(dividers);
}

void *read_write() {
    factor *dividers;
    long in_number;
    unsigned long number;
    long neg_number = 0;

    // Read input file line by line till the end of file (eof)
    while (!feof(f.in)) {
        fscanf(f.in, "%ld\n", &in_number); // Read number to be factored
	    /* Check if the number is > 2
	     * in this case skip the number and
	     * leave a message in the file
	     */
	    if((in_number > 2) || (in_number < -2)) {
            /* Verify if the number is prime or not, in this case the dividers are calculated */
            /* Handle negative number to calculate prime dividers *********NEW***********/
            if(in_number < -2) {
                neg_number = in_number;
            }
            number = abs(in_number);
            dividers = prime_divs(number); // Core function of the app //

            /* MUTEX LOCK - CONTROL OF CRITICAL ACCESS - START  */
            if (pthread_mutex_lock(&mutex_readwrite) != 0) {
                printf("\nmutex_lock-mutex_readwrite %s\n", strerror(errno));
                exit(EXIT_FAILURE);
            }
            /* Handle negative number to calculate prime dividers *********NEW********** */
            if (neg_number != 0) {
                in_number = neg_number;
                neg_number = 0;
            }
            if (dividers->cnt != 0) {
                /* fprintf(f.out, "%lu ", dividers->number); ********** OLD *********** */
                fprintf(f.out, "%ld", in_number); /* ********NEW********** */
                int i;
                for (i = 0; i < dividers->cnt; i++) {
                    fprintf(f.out, " %lu", dividers->prime_dividers[i]);
                }
            } else { // For internal command test
                fprintf(f.out, "%ld", in_number); /* ********NEW********** */
               /* fprintf(f.out, "%lu ", dividers->number); *********** OLD ********** */
            }
            /*  MUTEX UNLOCK - CONTROL OF CRITICAL ACCESS - END  */
            if (pthread_mutex_unlock(&mutex_readwrite) != 0) {
                printf("\nmutex_lock-mutex_readwrite %s\n", strerror(errno));
                exit(EXIT_FAILURE);
            }
            fprintf(f.out, "\n");
            free(dividers);
        } else {
            fprintf(f.out, "%ld\n", in_number);
	    }
    }
    pthread_exit((void *) 0); // thread exit: normal termination => 0
}

#define DEFAULT_NO_THREADS 2
#define MAX_NO_THREADS 20
// MAIN PROGRAMME
int main (int argc, char *argv[]) {

    // Input arguments
    char *inputfile;    // Input filemane (string)
    char *outputfile;   // Output filemane (string)
    char *thread_arg;   //
    int NO_THREADS = DEFAULT_NO_THREADS; // Define default number of threads

    /* WARNING: ONLY NUMBER POSITIVE AND >2 ARE ACCEPTED
     *printf("!!! WARNING: ONLY POSITIVE NUMBER AND >2 ARE ACCEPTED !!!\n");
     *printf("      OTHERWISE THE PROGRAMME CANNOT RUN CORRECTLY\n\n");
     */

    if (argc == 3) { // Check if the number of argument is correct
        inputfile = argv[1];
        outputfile = argv[2];
        printf("Thread number not mentioned\n");
        printf("The default threads number is %d\n", DEFAULT_NO_THREADS);
    } else if(argc == 5) {
        thread_arg = argv[1];
        if(strcmp(thread_arg, "-N") != 0) {
            printf("%s\n", "Wrong input of the option\n Use option  \"-N\"\n");
            exit(EXIT_FAILURE);
        }
        NO_THREADS = atoi(argv[2]);
        /* If the number of threads is <= 0 ************* VERSION UPDATE ***************
         * NO_THREADS is set to DEFAULT_NO_THREADS
         */
        if(NO_THREADS <= 0) {
            NO_THREADS = 1;
            printf("The threads number cannot be <= 0 - Threads number set to 1\n");
        }
        if(NO_THREADS > MAX_NO_THREADS) {
            printf("Threads requested > %d\n", MAX_NO_THREADS);
            exit(EXIT_FAILURE);
        }
        inputfile = argv[3];
        outputfile = argv[4];
    } else {
        printf("%s\n", "Many or few arguments\n");
        printf("Correct command syntax:\n");
        printf("./fact [-N number_of_threads] input_file.txt output_file.txt\n\n");
        exit(EXIT_FAILURE);
    }
 /*
  * START CLOCK to measure CPU time
  * calculate programme performance
  */
  /*
    clock_t start, end;
    double cpu_time_used;
    start = clock();
  */
    // Open input and output files
    f.in = fopen(inputfile, "r");
    f.out = fopen(outputfile, "a+");
    if ((f.in == NULL) || (f.out == NULL)) {
        printf("Incorrect input_file or output_file name\n");
        exit(EXIT_FAILURE);
    }

    pthread_t thread[NO_THREADS]; // thread IDs
    // INITIALIZE MUTEX "mutex_readwrite"
    if (pthread_mutex_init(&mutex_readwrite , NULL) != 0){
        printf("\n mutex init failed-mutex_readwrite\n");
        exit(EXIT_FAILURE);
    }
    int i;
    for (i = 0; i < NO_THREADS; i++) {
        pthread_create(&thread[i], NULL, (void*)read_write, NULL);
    }
    for (i = 0; i < NO_THREADS; i++) {
        pthread_join(thread[i], NULL);
    }
 /* END CLOCK to measure CPU time */
 /*
    end = clock();
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    fprintf(f.out, "\nThe programme execution needed %.3f seconds\n\n", cpu_time_used);
    printf("\nThe programme execution needed %.3f seconds", cpu_time_used);
    printf("\n -- Programme end --\n");
 */
    // Eliminate mutex "mutex_readwrite"
    if (pthread_mutex_destroy(&mutex_readwrite) != 0){
        printf("\nmutex_destroy-mutex_readwrite %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    fclose(f.in);
    fclose(f.out);
    return (EXIT_SUCCESS);
}