Pass Struct with an array and Index to access to Thread - c

For a prime factorization project, I need to pass a struct and a number (from the command line) to a thread. The below code is what I have so far. The factorization works fine, the problem is that the index passed to the thread isn't being passed in order, so the results vary, often storing data in the same index in a subsequent thread. Anyone know how to guarantee which index the thread will access, or a better way of implementing this? Each thread has to store their data in a struct so that the main thread can print all the data at the end, once all threads have closed.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
// Initialize Constants
#define MAX_ARGS 25
#define MAX_PRIMES 10
#define SMALLEST_ARG 2
// Define Struct
struct PrimeData {
int index;
int num_to_fact[MAX_ARGS];
int primes[MAX_ARGS][MAX_PRIMES];
};
// Declare Functions
void* factor (void*);
// Main
int main(int argc, char* argv[])
{
// Initialize Struct Variables
struct PrimeData data;
struct PrimeData* data_addr = &data;
data.index = 0;
for (int i = 0; i < MAX_ARGS; i++)
data.num_to_fact[i] = -1;
for (int i = 0; i < MAX_ARGS; i++) {
for (int j = 0; j < MAX_PRIMES; j++)
data.primes[i][j] = -1;
}
// Check for arguments
if (argc <= 1)
printf("Usage: ./p3 <number to factor>...\n");
else {
// Initialize Thread Handler list
pthread_t threads[argc - 1];
// Create a Thread per Argument
for (int i = 1; i < argc; i++) {
// Update shares structure
data.index = i - 1;
data.num_to_fact[i - 1] = atoi(argv[i]);
// Create thread
pthread_create(&threads[i - 1], NULL, factor, (void*)data_addr);
}
// Tell main to wait for threads to terminate
for (int i = 1; i < argc; i++)
pthread_join(threads[i - 1], NULL);
}
// Iterate through struct
for (int i = 0; i < MAX_ARGS; i++) {
if (data.num_to_fact[i] == -1)
break;
printf("%d: ", data.num_to_fact[i]);
for (int j = 0; j < MAX_PRIMES; j++) {
if (data.primes[i][j] == -1)
break;
printf("%d ", data.primes[i][j]);
}
printf("\n");
}
// Terminate
return 0;
}
// The factor() function
void* factor(void* data)
{
struct PrimeData* d = (struct PrimeData*)data;
int index = d->index;
int n = d->num_to_fact[index];
int counter = 0;
int i = 2;
while (n != 1) {
if (n % i == 0) {
while (n % i == 0) {
d->primes[index][counter] = i;
n = n / i;
counter++;
}
}
i++;
}
return NULL;
}

You have only one 'struct PrimeData data;', so there is no point in signaling the address of it in the pthread_create call. The messy way would be to globalize 'PrimeData' so the threads have access to it, array-ize the index: 'int index[MAX_ARGS];', load it with 0,1,2,3.. etc and then pass the address of the required index to each thread, eg '&data_addr[i-1]'.
It might be clearer if you accepted that C arrays are indexed from zero and so get rid of a lot of those [i-1] things.

I got it working using a mutex. Kind of odd, we do not cover mutexes until the next chapter. I eventually stumbled upon an article explaining that when you use multithreading where each thread is accessing a shared memory location (my struct in this case) then you have to use a mutex control the index:
// At the start of the program, before main
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int _index = -1;
// first three lines of the factor function
pthread_mutex_lock(&mutex1);
_index++;
pthread_mutex_unlock(&mutex1);

// Define Struct
struct PrimeData {
int num_to_fact[MAX_ARGS];
int primes[MAX_ARGS][MAX_PRIMES];
};
typedef struct Wrapper {
int index;
struct PrimeData *data;
} Wrapper;
...
int main(int argc, char *argv)
{
// ...
// Define wrappers
Wrapper wrappers[argc-1];
for (int i = 1; i < argc; i++)
{
wrappers[i-1].index = i;
wrappers[i-1].data = &data;
//...
pthread_create(&threads[i - 1], NULL, factor, wrappers + i - 1);
}
// ...
}
void *factor(void *wrapper)
{
Wrapper *w = (Wrapper *) wrapper;
struct PrimeData* d = w->data;
int index = w->index;
// ...
}

Related

Multithreading but first few threads are being skipped

It's been a few hours and i can't seem to understand the issue. Build this program to count from 1 - 10. The goal of this program is to use multithreading and dynamically split the array depending on how many threads it requested. Problem is the first 2 threads are being skipped and the last thread is doing most of th e process. I suspect it's the for loop that creates the threads.
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
typedef struct
{
int *array;
int batch;
int start;
int end;
} Parameter;
void *method(void *p)
{
Parameter *param = (Parameter *)p;
for (int i = param->start; i < param->end; i++)
{
printf("Start:%d\tEnd:%d\tIndex:%d\tValue:%d\n", param->start, param->end, i,param->array[i]);
}
}
int main(int argc, char **argv)
{
// Getting the user input
int array_length = atoi(argv[1]);
int batches = atoi(argv[2]);
printf("User specified Array:%d\tBatch:%d\n", array_length, batches);
// Creating an array
int *array = (int *)calloc(array_length, sizeof(int));
// Fill it up with some data
for (int i = 0; i < array_length; i++)
{
array[i] = i;
}
// Determine the Batches
int batch_size = array_length / batches;
int remainder = array_length % batches;
printf("%d\n", batch_size);
printf("%d\n", remainder);
int start = 0;
int end = 0;
int index =0;
// List of parameters
Parameter *param = (Parameter *)calloc(batches, sizeof(Parameter));
pthread_t *threads = (pthread_t *)calloc(batches, sizeof(pthread_t));
// Loop through each batch.
for (int i = 0; i < batches; i++)
{
printf("\n\nBatch number -> %d\n", i);
end = start + batch_size;
if (remainder > 0)
{
remainder --;
end ++;
}
// Fill the parameters
param[i].array = array;
param[i].end = end;
param[i].start = start;
param[i].batch = i;
// Call the thread.
pthread_create(threads + index, NULL, method, (void *)&param[i]);
index++;
start = end;
}
for (int i = 0; i < batches; i++)
{
pthread_join(threads[i], NULL);
}
free(param);
free(threads);
free(array);
return 0;
}
Been playing with the index of the for loop(line 57) as i'm certain it's the cause of the issue. been getting some results but the main problem still persisted.
Code Works as intended. I'm a dumbas who didn't put the printf in the void function. like so:
void *method(void *p) {
Parameter *param = (Parameter *)p;
printf("\n\nBatch number -> %d\n", param->batch); //<-- moved from main method
for (int i = param->start; i < param->end; i++)
{
printf("Start:%d\tEnd:%d\tIndex:%d\tValue:%d\n", param->start, param->end, i,param->array[i]);
} }
Thanks for pointing it out that the program works

Printing in order with c threads

Given this code:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
void *findPrimes(void *arg)
{
int val = *(int *)arg;
for (int i = val * 1000; i < val * 1000 + 1000; i++)
{
int isPrime = 1;
for (int j = 2; j < i; j++)
{
if (i % j == 0)
{
isPrime = 0;
break;
}
}
if (isPrime)
{
printf("%d\n", i);
}
}
pthread_exit(NULL);
}
int main()
{
pthread_t p[3];
int val[3] = {0, 1, 2};
for (int i = 0; i < 3; i++)
{
pthread_create(&p[i], NULL, findPrimes, &val[i]);
}
for (int i = 0; i < 3; i++)
{
pthread_join(p[i], NULL);
}
return 0;
}
Who prints in 3 threads all the prime number between 0 and 3000.
I want to print them in order, how can i do it?
My professor suggest to use an array of semaphore.
In order to synchronize the actions of all the threads I suggest using a pthread_mutex_t and a pthread_cond_t (a condition variable). You also need a way to share data between threads, so I'd create a struct for that:
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
typedef struct {
unsigned whos_turn;
pthread_mutex_t mtx;
pthread_cond_t cv;
} shared_data;
whos_turn will here be used to tell the threads whos turn it is to print the primes found.
Each thread also needs some thread-unique information. You called it val so I'll call it val here too. We can compare val with whos_turn to decide which thread it is that should print its result. In order to pass both the shared data and val to a thread, you can package that in a struct too:
typedef struct {
unsigned val;
shared_data *sd; // will point to the one and only instance of `shared_data`
} work_order;
Now, findPrimes need somewhere to store the primes it calculates before it's time to print them. Since the range to search is hardcoded, I'd just add an array for that:
#define SEARCH_RANGE (1000ULL)
void *findPrimes(void *arg) {
work_order *wo = arg;
uintmax_t primes[SEARCH_RANGE]; // to store the found primes
int found_count = 0;
for (uintmax_t i = wo->val*SEARCH_RANGE+1; i <= (wo->val+1)*SEARCH_RANGE; i += 2) {
bool isPrime = true;
for (uintmax_t j = 3; j < i; j += 2) {
if (i % j == 0) { // note: both i and j are odd
isPrime = false;
break;
}
}
if (isPrime) {
primes[found_count++] = i;
}
}
if(wo->val == 0) { // special case for the first range
primes[0] = 2; // 1 is not a prime, but 2 is.
}
// ... to be continued below ...
So far, nothing spectacular. The thread has now found all primes in its range and has come to the synchronizing part. The thread must
lock the mutex
wait for its turn (called "the predicate")
let other threads do the same
Here's one common pattern:
// ... continued from above ...
// synchronize
pthread_mutex_lock(&wo->sd->mtx); // lock the mutex
// only 1 thread at a time reaches here
// check the predicate: That is's this thread's turn to print
while(wo->val != wo->sd->whos_turn) { // <- the predicate
// if control enters here, it was not this thread's turn
// cond_wait internally "unlocks" the mutex to let other threads
// reach here and wait for the condition variable to get signalled
pthread_cond_wait(&wo->sd->cv, &wo->sd->mtx);
// and here the lock is only held by one thread at a time again
}
// only the thread whos turn it is reaches here
Now, the thread has reached the point where it is its time to print. It has the mutex lock so no other threads can reach this point at the same time.
// print the collected primes
for(int i = 0; i < found_count; ++i)
printf("%ju\n", primes[i]);
And hand over to the next thread in line to print the primes it has found:
// step the "whos_turn" indicator
wo->sd->whos_turn++;
pthread_mutex_unlock(&wo->sd->mtx); // release the mutex
pthread_cond_broadcast(&wo->sd->cv); // signal all threads to check the predicate
pthread_exit(NULL);
}
And it can be tied together quite neatly in main:
#define Size(x) (sizeof (x) / sizeof *(x))
int main() {
shared_data sd = {.whos_turn = 0,
.mtx = PTHREAD_MUTEX_INITIALIZER,
.cv = PTHREAD_COND_INITIALIZER};
pthread_t p[3];
work_order wos[Size(p)];
for (unsigned i = 0; i < Size(p); i++) {
wos[i].val = i; // the thread-unique information
wos[i].sd = &sd; // all threads will point at the same `shared_data`
pthread_create(&p[i], NULL, findPrimes, &wos[i]);
}
for (unsigned i = 0; i < Size(p); i++) {
pthread_join(p[i], NULL);
}
}
Demo

How do I pass an integer into the pthread_create function from argv? (C)

For this program I pass in numbers through the command line and then have a multithreaded program that takes each argument, calculates its factors, then prints them. I know c++, but I'm rough with c and can't seem to get the casting down correctly for this program. Specifically when I pass the argument into the thread_create and cast it to an integer. The code I have below compiles, but the value after the cast is always a 0. How do I cast the char value to a void* then to an integer?
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define MAX_ARRAY (17)
void *thread_func(void *);
int factors[MAX_ARRAY];
int main(int argc, char *argv[]) {
pthread_t thread_handle[argc];
int i;
int g;
// Create Children Threads
for ( i = 0; i < argc; i++ ) {
pthread_create(&thread_handle[i], NULL, thread_func, &argv[i + 1]);
}
// Rejoin Threads
for ( i = 0; i < argc; i++ ) {
pthread_join(thread_handle[i], NULL);
// Print Factors Here
printf("%d: ", atoi(argv[i]));
for ( g = 0; g < MAX_ARRAY; g++ ) {
printf("%d, ", factors[g]);
}
printf("\n");
for ( g = 0; g < MAX_ARRAY; g++ ) {
factors[g] = 0;
}
}
return 0;
}
void *thread_func(void *data) {
int n = atoi(data);
int x;
int v;
printf("Number to factor is: %d\n", n);
for ( x = 1; x <= n; ++x ) {
if (n%x == 0)
factors[v++] = x;
}
return NULL;
}
The problem is that each thread uses the same array for the factors, without any synchronization. But if each thread had to get a lock for the array before running, they would in effect all run in sequence which would defeat the purpose of threading.
Incidentally, argv[0] is the program name, which you should skip.
What you should do is have a different factor array for each thread, so that they can work independently without interference. You should also do all the display in the main thread, to control the order in which things are printed.
Since it is probably best to display the factors in order, you should first create all the threads, then join all of them, then finally display the results.
There were also a few small errors here and there like off by one errors or uninitialized variables.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_ARRAY 17
typedef struct {
int factors[MAX_ARRAY];
int n;
} thread_data;
void * thread_func (void *);
int main (int argc, char *argv[]) {
int n = argc - 1;
pthread_t thread_handle[n];
thread_data thread_data_table[n];
int i;
// Create Children Threads
for (i = 0; i < n; i++ ) {
thread_data_table[i].n = atoi (argv[i + 1]);
pthread_create(&thread_handle[i], NULL, thread_func,
&thread_data_table[i]);
}
// Join Threads
for (i = 0; i < n; i++ ) {
pthread_join(thread_handle[i], NULL);
}
// Print Factors
for (i = 0; i < n; i++) {
int j;
printf("%d: ", thread_data_table[i].n);
for (j = 0; j < MAX_ARRAY; j++ ) {
int x = thread_data_table[i].factors[j];
if (x == 0) {
break;
}
printf("%d, ", x);
}
printf("\n");
}
return 0;
}
void * thread_func (void *data)
{
thread_data *p = (thread_data*)data;
int i;
int count = 0;
for (i = 1; i <= p->n; ++i ) {
if (p->n % i == 0) {
if (count == MAX_ARRAY) {
break;
}
p->factors[count++] = i;
}
}
if (count < MAX_ARRAY) {
p->factors[count] = 0;
}
return NULL;
}

Calculate series with multithreading in C doesn't work as expected

I am trying to write a program in C that calculates the series:
for(i=0; i <= n; i++){
(2*i+1)/factorial(2*i);
}
n is the number of elements, determined by the user as an argument.
The user also determines the number of threads that are going to calculate the series.
I divide the series in subseries that calculate only a part of the series and each subseries should be calculated by a single thread. The problem is that my threads probably share memory because some series members are calculated many times and others are not calculated at all. Do you know why? Please help!
Here is the problematic part of the code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <gmp.h>
#include <math.h>
#include <pthread.h>
/* a struct to pass function arguments to the thread */
struct intervals_struct {
int **intervals;
mpf_t *result;
int thread_index;
};
/* calculate the sum of the elements of the subseries;
doesn't work properly for more than one thread */
void* sum_subinterval(void *args) {
/* Initialize the local variables here */
struct intervals_struct *p = (struct intervals_struct*)args;
for(i=(*p).intervals[(*p).thread_index][0]; i<=(*p).intervals[(*p).thread_index][1]; i++){
/* Do something with the local variables here */
}
mpf_set((*p).result[(*p).thread_index],sum);
/* Free resources used by the local variables here */
}
/* calculate the sum of all subseries */
void main(int argc, char * argv[]){
int p, t, i;
p = atoi(argv[1]);
assert( p >= 0);
t = atoi(argv[2]);
assert( t >= 0);
int **intervals_arr;
intervals_arr = (int**)malloc(t * sizeof(int *));
for(i = 0; i < t; i++) {
intervals_arr[i] = (int *)malloc(2 * sizeof(int));
}
/* Calculate intervals and store them in intervals_arr here */
mpf_t *subinterval_sum;
subinterval_sum = (mpf_t*)malloc(t * sizeof(mpf_t));
for(i=0; i < t; i++) {
mpf_init(subinterval_sum[i]);
}
pthread_t *tid;
tid = (pthread_t *)malloc(t * sizeof(pthread_t));
for(i = 0; i < t; i++) {
struct intervals_struct args = {intervals_arr, subinterval_sum, i};
pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args);
}
for(i = 0; i < t; i++) {
pthread_join(tid[i], NULL);
}
/* Sum the elements of the result array and free resources used in main here */
}
The problem is probably here:
for(i = 0; i < t; i++) {
struct intervals_struct args = {intervals_arr, subinterval_sum, i};
pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args);
}
You are passing the address of args to your new thread, but the lifetime of that variable ended immediately after the pthread_create call. The compiler can and will reuse the stack space occupied by args between different loop iterations.
Try allocating an array on the heap with malloc instead.
Edit: What I meant by that last sentence is something like this:
struct intervals_struct * args = (struct intervals_struct *) calloc(t, sizeof(struct intervals_struct));
for(i = 0; i < t; i++) {
args[i].intervals = intervals_arr;
args[i].result = subinterval_sum;
args[i].thread_index = i;
pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args[i]);
}
// at the end of main(), or at least after every thread has been joined
free(args);

Reading array from threads, c, cygwin

I'm pretty new to threads and would like some insight. I'm trying to get the percentage each thread has completed for its calculation. Each thread will report its percentage to a different element of the same array. I have this working with pthread_join immediately after pthread_create and a separate thread for reading all the values of the array and printing the percentage but when I have all threads running after each other without waiting for the previous one to finish I get some weird behavior. This is how I'm accessing the shared (global) array.
//global
int *currentProgress;
//main
currentProgress = malloc(sizeof(int)*threads);
for(i=0; i<threads; i++)
currentProgress[i] = 0;
//child threads
currentProgress[myId] = (int)percent; //myId is unique
//progress thread
for(i=0; i<threads; i++)
progressTotal += currentProgress[i];
progressTotal /= threads;
printf("Percent: %d", progressTotal);
This is essentially the code I think is not being used correctly for multi-threads. When I print out the state of the shared array, I notice that as soon as another thread starts accessing the array (different element though), the previous element immediately goes to some random number... -2147483648 and when the latter element finishes the prior element continues like normal. Should I be using semaphores for this? I thought I could access different elements of an array at the same time and I thought reading them wasn't an issue.
This is the entire code:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#define STDIN 0
int counter = 0;
uint64_t *factors;
void *getFactors(void *arg);
void *deleteThreads(void *arg);
void *displayProgressThread(void *arg);
int *currentProgress;
struct data
{
uint64_t num;
uint64_t incrS;
uint64_t incrF;
int threads;
int member;
} *args;
int main(int argc, char *argv[])
{
if(argc < 3) {printf("not enough arguments"); exit(1);}
int i;
int threads = atoi(argv[2]);
pthread_t thread_id[threads];
pthread_t dThread;
currentProgress = malloc(sizeof(int)*threads);
for(i=0; i<threads; i++)
currentProgress[i] = 0;
args = (struct data*)malloc(sizeof(struct data));
args->num = atoll(argv[1]);
args->threads = threads;
uint64_t increment = (uint64_t)sqrt((uint64_t)args->num)/threads;
factors = (uint64_t*)malloc(sizeof(uint64_t)*increment*threads);
pthread_create(&dThread, NULL, displayProgressThread, (void*)args);
//for the id of each thread
args->member = 0;
for(i=0; i<threads; i++)
{
args->incrS = (i)*increment +1;
args->incrF = (i+1)*increment +1;
pthread_create(&thread_id[i], NULL, getFactors, (void*)args);
usleep(5);
}
for(i=0; i<threads; i++)
{
pthread_join(thread_id[i], NULL);
}
sleep(1);
printf("done\n");
for (i=0; i<counter; i++)
printf("\n%llu : %llu", factors[++i], factors[i]);
return 0;
}
void *getFactors(void *arg)
{
uint64_t count;
int myId;
int tempCounter = 0, i;
struct data *temp = (struct data *) arg;
uint64_t number = temp->num;
float total = temp->incrF - temp->incrS, percent;
myId = temp->member++;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
for(count=temp->incrS; count<=temp->incrF; count++)
{
percent = (float)(count-temp->incrS)/total*100;
currentProgress[myId] = (int)percent;
if (number%count == 0)
{
factors[counter++] = count;
factors[counter++] = number/count;
}
usleep(1);
}
usleep(1);
pthread_exit(NULL);
}
void *displayProgressThread(void *arg)
{
struct data *temp = (struct data *) arg;
int toDelete = 0;
while(1)
{
int i;
int progressTotal = 0;
char *percent = malloc(sizeof(char)*20);
for(i=0; i<toDelete; i++)
printf("\b \b");
for(i=0; i<temp->threads; i++){
progressTotal += currentProgress[i];
}
progressTotal /= temp->threads;
printf("|");
for(i=0; i<50; i++)
if(i<progressTotal/2)
printf("#");
else
printf("_");
printf("| ");
sprintf(percent, "Percent: %d", progressTotal);
printf("%s", percent);
toDelete = 53 + strlen(percent);
usleep(1000);
fflush(stdout);
if(progressTotal >= 100)
pthread_exit(NULL);
}
}
There are some non synchronized pieces of code that are accessed by the threads which cause this problem.
One first place to be synchronized is:
myId = temp->member++;
But more importantly is that, the main thread is doing:
args->incrS = (i)*increment +1;
args->incrF = (i+1)*increment +1;
while at the same time in the threads:
for(count=temp->incrS; count<= temp->incrF; count++)
{
percent = (float)(count-temp->incrS)/total*100;
currentProgress[myId] = (int)percent;
if (number%count == 0)
{
factors[counter++] = count;
factors[counter++] = number/count;
}
usleep(1);
}
The unsynchronized accesses mentioned above affect the calculation of percent value which results in such abnormal happenings. You have to do synchronization in all these places in order to get the kind of behavior you would expect.

Resources