SA.93
SA.93

Reputation: 151

Practice using threads simultaneously on same argument


I'm practicing the use of multiple threads in C language (Linux OS). I wrote a simple code to find the divisors of a number, if the number has no divisors (excluding 1 and the number itself) then it's a prime number.
The find_div function checks in a loop if the number which was run from the thread creation has any divisors.
My issue is that both threads are running separately. I've tried splitting the number, but obviously that method removes options (since the number sent is not the original one). Also tried using a global index for the loop run (thought each thread will use the "new" index when it's incremented, didn't work because of synchronization issues).
I don't know how to continue, would love tips and hints on how I should move forward with this (or if there is a way to make the global index method work?).
The code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int prime, i;

void *find_div(void *f);

void main(int argc, char* argv[]){
    if(argc < 2){
        fprintf(stderr, "Must enter one number\n");
        exit(1);
    }

    int n;
    pthread_t thread[2];

    prime = 0; //Initialize
    n = atoi(argv[1]);

    if((pthread_create(&thread[0], NULL, find_div, (void *)n)) != 0){
        perror("thread");
        exit(1);
    }

    if((pthread_create(&thread[1], NULL, find_div, (void *)n)) != 0){
        perror("thread");
        exit(1);
    }

    pthread_join(thread[0], NULL);
    pthread_join(thread[1], NULL);

    if(prime == 0)
        fprintf(stdout, "%d is prime number\n", n);
    else
        fprintf(stdout, "\n");
}

void *find_div(void *f){
    for (i=2; i<(int)f; i++){ //Start from 2 since 1 is a divisor to all Natural numbers (and every Natural number is a divisor to itself)
        if ((int)f%i == 0){
            printf("%d ", i);
            prime = 1; //Meaning not prime number
        }
    }
}

The output if the number is 6:

2 3 2 3

Upvotes: 0

Views: 184

Answers (2)

SA.93
SA.93

Reputation: 151

I've tried creating a struct to contain the arguments which needed to be passed according to the answers received - no success in using the threads ids. But the method gave me an idea of how to work around this (although it's not an ideal way):

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int prime = 0, divisor = 0;

void *find_div1(void *s);
void *find_div2(void *s);

void main(int argc, char* argv[]){
    if(argc < 2){
        fprintf(stderr, "Must enter one number\n");
        exit(1);
    }
    
    int n;
    pthread_t thread[2];
    n = atoi(argv[1]);

    if((pthread_create(&thread[0], NULL, find_div1, (void *)n)) != 0){
        perror("thread");
        exit(1);
    }

    if((pthread_create(&thread[1], NULL, find_div2, (void *)n)) != 0){
        perror("thread");
        exit(1);
    }

    pthread_join(thread[0], NULL);
    pthread_join(thread[1], NULL); //Wait for both threads to finish

    if(prime == 0)
        fprintf(stdout, "%d is prime number\n", n);
    else
        fprintf(stdout, "\n");
}

void *find_div1(void *s){
    int num = (int)s;
    int start, end, i;
    
    if(num < 4)
        return;

    start = 2;
    end = num/2;

    for (i=start; i<end; i++){ 
        if (num%i == 0){
            if(divisor == 0){
                divisor = 1;
                fprintf(stdout, "Divisors of %d:\n", num);
            }
            printf("%d\n", i);
            prime = 1; //Meaning not prime number
        }
    }
}

void *find_div2(void *s){
    int num = (int)s;
    int start, end, i;

    if(num < 4)
        return;

    start = num/2;
    end = num;

    for (i=start; i<end; i++){ 
        if (num%i == 0){
            if(divisor == 0){
                divisor = 1;
                fprintf(stdout, "Divisors of %d:\n", num);
            }
            printf("%d\n", i);
            prime = 1; 
        }
    }
}

EDIT:
This is the code after the answer:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int prime = 0, divisor = 0;

void *find_div(void *s);

struct my_args{
    int num;
    char id; //Will identify the thread running
};

void main(int argc, char* argv[]){
    if(argc < 2){
        fprintf(stderr, "Must enter one number\n");
        exit(1);
    }
    
    struct my_args arg1, arg2;

    arg1.num = atoi(argv[1]);
    arg1.id = 'a';
    arg2.num = atoi(argv[1]);
    arg2.id = 'b';

    pthread_t thread[2];

    if((pthread_create(&thread[0], NULL, find_div, (void *)&arg1)) != 0){
        perror("thread");
        exit(1);
    }

    if((pthread_create(&thread[1], NULL, find_div, (void *)&arg2)) != 0){
        perror("thread");
        exit(1);
    }

    pthread_join(thread[0], NULL);
    pthread_join(thread[1], NULL); //Wait for both threads to finish

    if(prime == 0)
        fprintf(stdout, "%d is prime number\n", atoi(argv[1]));
    else
        fprintf(stdout, "\n");
}

void *find_div(void *s){
    struct my_args *pArg = (struct my_args *)s;
    int num = pArg->num;
    char tid = pArg->id;

    int start, end, i;

    if(tid == 'a'){
        start = 2;
        end = num/2;
    }
    else{
        start = num/2;
        end = num;
    }

    for (i=start; i<end; i++){ //Start from 2 since 1 is a divisor to all Natural numbers (and every Natural number is a divisor to itself)
        if (num%i == 0){
            if(divisor == 0){
                fprintf(stdout, "Divisors of %d:\n", num);
                divisor = 1;
            }
            printf("%d\n", i);
            prime = 1; //Meaning not prime number
        }
    }
}

Upvotes: 0

Ashutosh Raghuwanshi
Ashutosh Raghuwanshi

Reputation: 440

You can implement it in this way. Pass two parameters instead of one to find_div function. The second parameter should be thread number. For this you can use and array int param[2] where param[0] will have n and param[1] will have thread number. Then find_div can be implemented this way:

void *find_div(void *f){

    int num = ((int*)f)[0];
    int tid = ((int*)f)[1];
    int start, end;

    if(tid == 0)
    {
        start = 2;
        end = num/2;
    }
    else
    {
        start = num/2;
        end = num;
    }

    for (i=start; i<end; i++){ //Start from 2 since 1 is a divisor to all Natural numbers (and every Natural number is a divisor to itself)

        if (num%i == 0){

            printf("%d ", i);

            prime = 1; //Meaning not prime number

        }

    }

}

UPDATE

Based on your commend and original code I believe you need to understand the thread parameter type void *. In your code int n; was passed as (void *)n it worked because a pointer is of same size as an int but that is not the correct way. Correct way is to pass (void *)&n and inside thread function use it as *(int*)f. Let me demonstrate how to pass a struct and use it.

void *find_div(void *f);

struct MyData {
  int num;
  char chr;
};

void main(int argc, char* argv[]){

//... initial code 

    struct MyData data;
    data.num = 10;
    data.chr = 'a';
    pthread_t thread[2];

    if((pthread_create(&thread[0], NULL, find_div, (void *)&data)) != 0){
        perror("thread");
        exit(1);
    }

    //... rest of code
}

Then in your thread function you can use the parameter like this.

void *find_div(void *f){

    struct MyData *pData = ((MyData*)f);
    int tid = pData->num;
    char chrData = pData->chr;

// ... rest of the code
}

Hopefully this will help you do what you need to do.

Upvotes: 1

Related Questions