Reputation: 115
I am learning pthreads.
Right now I am trying to make the program that writes to one 2d array
using multiple pthreads
. Each pthread
is responsible for only one line of the array
. So there is no race or overlap there.
The goal is to make it as fast as possible without using global variables.
The first solution that I implemented was the one that uses a global variable
. And it works as intended. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int **array;
const int NTHREADS = 5;
const int ELEMENTS = 3;
void *worker(void *arg);
void print_array(int **array);
int main()
{
int i, j;
pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
array = (int**)malloc(sizeof(int*));
for(i = -1; i < NTHREADS; i++)
{
array[i] = (int*)malloc(sizeof(int));
for (j = -1; j < ELEMENTS; j++)
{
array[i][j] = (int)malloc(sizeof(int));
}
}
for (i = 0; i < NTHREADS; i++)
pthread_create(&threads[i], NULL, worker, (void*)i);
for (i = 0; i < NTHREADS; i++)
pthread_join(threads[i], NULL);
print_array(array);
return 0;
}
void *worker(void *arg)
{
int tid = (int)arg;
for (int j = 0; j < ELEMENTS; j++)
array[tid][j] = j;
return (NULL);
}
void print_array(int **array)
{
for (int i = 0; i < NTHREADS; i++)
{
for (int j = 0; j < ELEMENTS; j++)
printf("%d,", array[i][j]);
printf("\n");
}
}
Then I wrote the same program using struct
instead of global variable
. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
const int NTHREADS = 5;
const int ELEMENTS = 3;
typedef struct s_asd
{
int **array;
int tid;
} t_asd;
void *worker(void *arg);
void print_array(int **array);
int main()
{
pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
t_asd tmp;
int i, j;
tmp.array = (int**)malloc(sizeof(int*));
for (i = 0; i <= NTHREADS; i++)
{
tmp.array[i] = (int*)malloc(sizeof(int));
for (j = 0; j <= ELEMENTS; j++)
tmp.array[i][j] = (int)malloc(sizeof(int));
}
for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++)
pthread_create(&threads[tmp.tid], NULL, worker, &tmp);
for (i = 0; i < NTHREADS; i++)
pthread_join(threads[i], NULL);
print_array(tmp.array);
return 0;
}
void *worker(void *arg)
{
t_asd *tmp = (t_asd*)arg;
for (int j = 0; j < ELEMENTS; j++)
tmp->array[tmp->tid][j] = j;
return (NULL);
}
void print_array(int **array)
{
for (int i = 0; i < NTHREADS; i++)
{
for (int j = 0; j < ELEMENTS; j++)
printf("%d,", array[i][j]);
printf("\n");
}
}
This one, prints random numbers. I know that I am using the same pointer in all threads, but threads themselves, are not using the same memory area. So why does it prints random numbers? What is the best solution, without using a global variable?
Update 1. Output of the second program:
-1413467520,32668,-1413467440,
-1413467584,-1413467568,-1413467552,
-1413467504,-1413467488,-1413467472,
0,1,2,
0,1,2,
Upvotes: 0
Views: 2261
Reputation: 1162
Try something like that :
int main()
{
pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
t_asd tmp;
int i, j;
tmp.array = (int**)malloc(NTHREADS * sizeof(int*));
for (i = 0; i <= NTHREADS; i++)
{
tmp.array[i] = (int*)malloc(ELEMENTS * sizeof(int));
//can be deleted if you want
for (j = 0; j <= ELEMENTS; j++)
tmp.array[i][j] = 0;
}
for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++) {
t_asd *arg = (t_asd *) malloc(sizeof(t_asd));
memcpy(arg, &tmp, sizeof(t_asd)); //will copy the current tid and the pointer to the array in a new memory area
pthread_create(&threads[tmp.tid], NULL, worker, arg);
}
for (i = 0; i < NTHREADS; i++)
pthread_join(threads[i], NULL);
print_array(tmp.array);
return 0;
}
Of course this is an example and you have to free all the allocations
Upvotes: 1
Reputation: 8534
You are passing local variable tmp as an argument to the thread and changing it in a loop at the same time. This is a data race and your threads most probably will operate over the same data.
Convert tmp to an array, fill and pass a corresponding element to a corresponding thread.
Upvotes: 1