I can't figure out where the problem is. I'm guessing it is either the way I'm using pthread_create or the way I multiply the index. Can someone help me figure it out? I would like to in the same struct I used.
When I compile it, it returns
28 23 18
41 34 27
54 45 36
*** stack smashing detected ./matrix terminated
Aborted (core dumped)
The code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define M 3
#define K 2
#define N 3
int A [M][K] ={{1,4},{2,5},{3,6}};
int B [K][N] ={{8,7,6},{5,4,3}};
int C [M][N];
/* structure for passing data to threads */
struct v
{
int i; /* row */
int j; /* column */
};
void *matrix_multiplication( void *ptr ); //the thread
int main (int argc, char* argv[]){
pthread_t workers[M*N];
int iret1;
int i = 0;
int j = 0;
int a = 1;
/* We have to create M * N worker threads */
for (i = 0; i < M ; i++) {
for (j = 0; j < N; j++){
struct v *data = (struct v *) malloc (sizeof(struct v));
data->i = i;
data->j = j;
/* Now create the thread passing it data as a parameter */
iret1 = pthread_create(&workers[a] , NULL , matrix_multiplication, (void *) data );
a++;
//free(data);
}
}
//wait for all the threads to be finished
for (i = 0; i<10 ; i++){
pthread_join(workers[i], NULL);
}
//printing the matrix
for (i = 0; i < M ; i++) {
for (j = 0; j < N; j++){
printf("%d ",C[i][j] );
}
printf("\n");
}
return 0;
}
void *matrix_multiplication( void *ptr ){
struct v *data = ptr;
int sum = 0, z;
for(z=0; z < K; z++){
sum += A[data->i][z] * B[z][data->j];
}
C[data->i][data->j] = sum;
printf("%d\n",sum );
//threads exit
pthread_exit(0);
}
You have a couple of small errors:
When you create the threads with
pthread_create(&workers[a], ...
a is in the first call already 1, because you've initialized it with 1. That
means that the last pthread_create call will access workers out of
bounds, you are passing a pointer to an undefined address and this is undefined
behaviour. You should initialize a with 0.
The second problem is when you join the threads:
for (i = 0; i<10 ; i++){
pthread_join(workers[i], NULL);
}
Because of a being initialized with 1, worker[0] is not an initialized
thread. The man page does not mention what happens when you pass an
uninitialized thread to pthread_join, but my guess is that it is undefined behaviour and most likely the reason
why you have the segfault. I would also write the condition i < M*N, because
if you change any of those values, you would be accessing workers out of
bounds.
You fail to free the memory for the struct v objects, you would have to do it
after the join. You are leaking memory there. I don't think that you even need
to use malloc here, you can declare an array of dimension M*N of struct v
objects, just like you did with the pthread_t array. When accessing the array,
I'd use i*N+j to calculate the correct index for both arrays.
I modified your code with my corrections and my suggestions:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define M 3
#define K 2
#define N 3
int A [M][K] ={{1,4},{2,5},{3,6}};
int B [K][N] ={{8,7,6},{5,4,3}};
int C [M][N];
/* structure for passing data to threads */
struct v
{
int i; /* row */
int j; /* column */
};
void *matrix_multiplication( void *ptr ); //the thread
int main (int argc, char* argv[]){
pthread_t workers[M*N];
struct v data[M*N];
int i = 0;
int j = 0;
/* We have to create M * N worker threads */
for (i = 0; i < M ; i++) {
for (j = 0; j < N; j++){
int idx = i*N+j;
data[idx].i = i;
data[idx].j = j;
/* Now create the thread passing it data as a parameter */
pthread_create(workers + idx, NULL, matrix_multiplication, data+idx);
}
}
//wait for all the threads to be finished
for (i = 0; i<M*N ; i++)
pthread_join(workers[i], NULL);
//printing the matrix
for (i = 0; i < M ; i++) {
for (j = 0; j < N; j++){
printf("%d ",C[i][j] );
}
printf("\n");
}
return 0;
}
void *matrix_multiplication( void *ptr ){
struct v *data = ptr;
int sum = 0, z;
for(z=0; z < K; z++){
sum += A[data->i][z] * B[z][data->j];
}
C[data->i][data->j] = sum;
printf("%d\n",sum );
pthread_exit(0);
}
As you see, I don't use malloc, so I don't have to worry about freeing memory
afterwards. When I run this code, I get:
41
45
18
28
27
34
23
54
36
28 23 18
41 34 27
54 45 36
edit
OP asked in the comment section
How can I free memory If I used malloc for the struct?!
There are different ways, but the first step is to store the pointer that
malloc returns. Right now you are not storing that value.
The first option would be: free the memory in the thread. Let's use your way of
passing values to the threads:
struct v *data = malloc(sizeof(struct v));
data->i = i;
data->j = j;
/* Now create the thread passing it data as a parameter */
pthread_create(&workers[a] , NULL , matrix_multiplication, data);
Every single thread get's an own struct v object and you never use it outside
the thread. That's why you can do this in the thread:
void *matrix_multiplication( void *ptr ) {
...
free(ptr);
pthread_exit(0);
}
Let's say that the parent process needs to get the pointer passed to the thread.
For example because the thread wrote some value there that the main
threads wants to evaluate. Let's say the threads should calculate their
calculation time. Your struct v could look like this:
struct v {
int i;
int j;
double time;
}
The threads would calculate the time and write it on data->time. The
thread can pass to the main thread a pointer through pthread_exit, in this
case you the thread can pass the same pointer it got from the main thread:
#include <time.h>
void *matrix_multiplication( void *ptr ){
struct v *data = ptr;
int sum = 0, z;
clock_t begin = clock();
for(z=0; z < K; z++){
sum += A[data->i][z] * B[z][data->j];
}
C[data->i][data->j] = sum;
clock_t end = clock();
data->time = (double)(end - begin) / CLOCKS_PER_SEC;
//threads exit
pthread_exit(ptr);
}
Now when you joing the threads, you get the pointer you've pass to the thread,
you can use that pointer and then free it if you don't need it anymore.
double agg_time = 0;
for (i = 0; i<M*N ; i++) {
struct v *data;
pthread_join(workers[i], (void**) &data);
printf("i: %d, j: %d ,time: %lf\n", data->i, data->j, data->time);
agg_time += data->time;
free(data);
}
printf("aggregated time: %lf\n", agg_time);
The output of this would be
i: 0, j: 0 ,time: 0.000002
i: 0, j: 1 ,time: 0.000001
i: 0, j: 2 ,time: 0.000002
i: 1, j: 0 ,time: 0.000002
i: 1, j: 1 ,time: 0.000001
i: 1, j: 2 ,time: 0.000001
i: 2, j: 0 ,time: 0.000002
i: 2, j: 1 ,time: 0.000001
i: 2, j: 2 ,time: 0.000014
aggregated time: 0.000026
28 23 18
41 34 27
54 45 36
If you pass a malloced pointer to the threads, this is the one I like the most.
A third option would be to store the malloc data in an array and free it after
the join.
int main(void)
{
...
struct v *data[M*N];
...
for (i = 0; i < M ; i++) {
for (j = 0; j < N; j++) {
int idx = i*N+j;
data[idx] = malloc(sizeof *data[idx]);
data[idx]->i = i;
data[idx]->j = j;
pthread_create(workers + idx, NULL, matrix_multiplication, data[idx]);
}
}
// do the join
for (i = 0; i<M*N ; i++){
pthread_join(workers[i], NULL);
}
// do the free
for(int i = 0; i < M*N; ++i)
free(data[i]);
}
I don't like this version too much, because it makes the code larger, you need
to check that malloc doesn't return NULL (I've omitted this test) and have
an error handling strategy for when it fails. That was the nice thing about my very
first code, you don't do malloc, you don't have to worry about free. However
if you need to pass an allocated block of memory to the thread, I'd do the one
above, where the thread returns the pointer back to the main thread through
pthread_exit.
Related
I have built this code utilizing pthreads. The goal is to build an array X[N][D] and assign random values to it. You could read the elements of this array as the coefficients of some points.
On the next step I am trying to calculate an array distances[N]which holds all the distances between the last element (Nth) and each other element. The distances calculation is executed using pthreads.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
#define N 10
#define D 2 //works for any d
#define NUM_THREADS 8
//double *distances;
//int global_index = 0;
pthread_mutex_t lock;
double *X;
typedef struct
{
//int thread_id;
double *distances;
int *global_index ;
pthread_mutex_t lock;
double *X;
}parms;
void *threadDistance(void *arg)
{
parms *data = (parms *) arg;
double *distances = data->distances;
double *X = data->X;
int *global_idx = data -> global_index;
int idx,j;
//long id = (long)arg;
pthread_mutex_lock(&lock);
while(*global_idx<N)
{
//printf("Thread #%ld , is calculating\n", id);
idx = *(global_idx);
(*global_idx)++;
pthread_mutex_unlock(&lock);
for(j=0 ; j<D; j++)
{
distances[idx] = pow(X[(j+1)*N-1]-X[j*N+idx], 2);
//printf("dis[%d]= ", dis);
//printf("%f\n",distances[idx]);
}
//printf("global : %d\n", *global_idx);
}
pthread_exit(NULL);
}
void calcDistance(double * X, int n, int d)
{
int i;
int temp=0;
pthread_t threads[NUM_THREADS];
double *distances = malloc(n * sizeof(double));
parms arg;
arg.X = X;
arg.distances = distances;
arg.global_index = &temp;
for (i=0 ; i<NUM_THREADS ; i++)
{
pthread_create(&threads[i], NULL, threadDistance, (void *) &arg);
}
for(i = 0 ; i<NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
/*----print dstances[] array-------*/
printf("--------\n");
for(int i = 0; i<N; i++)
{
printf("%f\n", distances[i]);
}
/*------------*/
free(distances);
}
int main()
{
srand(time(NULL));
//allocate the proper space for X
X = malloc(D*N*(sizeof(double)));
//fill X with numbers in space (0,1)
for(int i = 0 ; i<N ; i++)
{
for(int j=0; j<D; j++)
{
X[i+j*N] = (double) (rand() / (RAND_MAX + 2.0));
}
}
calcDistance(X, N, D);
return 0;
}
The problem is that the code executes completely only when N=100000. If N!=100000 the code just hangs and I have found that the source of the problem is the pthread_join() function. First of all I cannot understand why the hang depends on the value of N.
Secondly, I have tried printf()ing the value of global_index (as you can see it is commented out in this particular sample of code). As soon as I uncomment the printf("global : %d\n", *global_idx); command the program stops hanging, regardless of the value of N.
It seems crazy to me as the differences between hanging and not hanging are so irrelevant.
regarding:
pthread_mutex_lock(&lock);
while(*global_idx<N)
{
// ...
pthread_mutex_unlock(&lock);
The result is that after the first iteration of the loop, the mutex is always unlocked. Suggest moving the call to pthread_mutex_lock() to inside the top of the loop.
after making the above corrections, I then set N to 10000. Then re-compiled, etc. The result was a seg fault event, so the mis-handling of the mutex is not the only problem.
regarding:
* First of all I cannot understand why the hang depends on the value of N.*
it seems the program is actually crashing with a seg fault event, not hanging
I am trying to multiply two matrices using a different thread for each member of the resultant matrix. I have this code:
struct data{
int p;
int linie[20];
int coloana[20];
};
void *func(void *args){
struct data *st = (struct data *) args;
int c = 0;
for(int k = 0; k < st->p; k++){
c += st->linie[k] * st->coloana[k];
}
char *rez = (char*) malloc(5);
sprintf(rez, "%d", c);
return rez;
}
int main(int argc, char *argv[]){
int n = 2;
int m = 2;
int A[2][2] = {{1, 2},
{4, 5}};
int B[2][2] = {{7, 3},
{7, 5}};
int C[n][m];
char *res[n * m];
char *rez[n * m];
pthread_t threads[n * m];
int count = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
struct data st;
st.p = 2;
for(int x = 0; x < st.p; x++){
st.linie[x] = A[i][x];
st.coloana[x] = B[x][j];
}
pthread_create(&threads[count], NULL, func, &st);
count++;
}
}
for(int i = 0; i < n * m; i++){
pthread_join(threads[i], (void**) &rez[i]);
printf("%d ", atoi(rez[i]));
}
return 0;
}
But the correct result is never put into rez[i]. For example I get output "63 37 37 37".
The code works perfectly if I don't choose to wait for every thread to finish, i.e. I put that pthread_join right after pthread_create in the nested for loop. What should I do?
Thanks for reading!
Your first threading problem is here:
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
struct data st;
st.p = 2;
for(int x = 0; x < st.p; x++){
st.linie[x] = A[i][x];
st.coloana[x] = B[x][j];
}
pthread_create(&threads[count], NULL, func, &st);
count++;
}
}
All the threads get passed a pointer to the same variable, &st, which goes out of scope after each call to pthread_create(). You need to ensure that each thread gets its own variable, and that the variable lasts until the thread exits.
To fix this, for example, you could try:
struct data st[n * m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
st[count].p = 2;
for (int x = 0; x < st[count].p; x++)
{
st[count].linie[x] = A[i][x];
st[count].coloana[x] = B[x][j];
}
int rc = pthread_create(&threads[count], NULL, func, &st[count]);
if (rc != 0)
…report pthread creation error…
count++;
}
}
This gives each thread its own struct data to work on, and the structure outlasts the pthread_join() loop.
I'm not completely that it is a good scheme to make one copy of the relevant parts of the two arrays for each thread. It's not too painful at size 2x2, but at 20x20, it begins to be painful. The threads should be told which row and column to process, and should be given pointers to the source matrices, and so on. As long as no thread modifies the source matrices, there isn't a problem reading the data.
Updated answer which replaces the previous invalid code related to pthread_join() (as noted by oftigus in a comment) with this working code. There's a reason I normally test before I post!
On the whole, casts like (void **) should be avoided in the pthread_join() loop. One correct working way to handle this is:
for (int i = 0; i < n * m; i++)
{
void *vp;
int rc = pthread_join(threads[i], &vp);
if (rc == 0 && vp != NULL)
{
rez[i] = vp;
printf("(%s) %d ", rez[i], atoi(rez[i]));
free(rez[i]);
}
}
putchar('\n');
This passes a pointer to a void * variable to pthread_join(). If it finds the information for the requested thread, then pthread_join() makes that void * variable hold the value returned by the thread function. This can then be used as shown — note the error handling (though I note that the example in the POSIX specification for pthread_join()ignores the return value from pthread_join() with a (void) cast on the result).
I don't see where you use res or C.
The result I get is:
(21) 21 (13) 13 (63) 63 (37) 37
where the value in parentheses is a string and the value outside is converted by atoi(). That looks like the correct answer for multiplying A by B (in that order).
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct data
{
int p;
int linie[20];
int coloana[20];
};
static void *func(void *args)
{
struct data *st = (struct data *)args;
int c = 0;
for (int k = 0; k < st->p; k++)
{
c += st->linie[k] * st->coloana[k];
}
char *rez = (char *)malloc(5);
sprintf(rez, "%d", c);
return rez;
}
int main(void)
{
int n = 2;
int m = 2;
int A[2][2] = {{1, 2}, {4, 5}};
int B[2][2] = {{7, 3}, {7, 5}};
char *rez[n * m];
pthread_t threads[n * m];
int count = 0;
struct data st[n * m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
st[count].p = 2;
for (int x = 0; x < st[count].p; x++)
{
st[count].linie[x] = A[i][x];
st[count].coloana[x] = B[x][j];
}
int rc = pthread_create(&threads[count], NULL, func, &st[count]);
if (rc != 0)
{
fprintf(stderr, "Failed to create thread %d for cell C[%d][%d]\n", count, i, j);
exit(1);
}
count++;
}
}
for (int i = 0; i < n * m; i++)
{
void *vp;
int rc = pthread_join(threads[i], &vp);
if (rc == 0 && vp != NULL)
{
rez[i] = vp;
printf("(%s) %d ", rez[i], atoi(rez[i]));
free(rez[i]);
}
}
putchar('\n');
return 0;
}
I want to read as input a table A and B from a user , and make an inner product space from them (a1b1+a2b2+……+anbn) and save it in a local_sum and then share it to an total_sum variable. I am doing the bellow code , but there is a segment fault. For some reason table A & B can't pass to function MUL. Any help would be great, thank you!
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define N 2
int p;
int A[N],B[N];
int local_sum;
void *mul(void *arg)
{
int lines, start, end, i, j;
int id = *(int*)arg;
lines = N / p;
start = id * lines;
end = start + lines;
for (i = start; i < end; i++)
local_sum = A[i] * B[i] + local_sum;
return NULL;
}
int main (int argc, char *argv[])
{
int i;
pthread_t *tid;
if (argc != 2)
{
printf("Provide number of threads.\n");
exit(1);
}
p = atoi(argv[1]);
tid = (pthread_t *)malloc(p * sizeof(pthread_t));
if (tid == NULL)
{
printf("Could not allocate memory.\n");
exit(1);
}
printf("Give Table A\n");
for (int i = 0; i < N; i++)
{
scanf("%d", &A[i]);
}
printf("Give Table B\n");
for (int i = 0; i < N; i++)
{
scanf("%d", &B[i]);
}
for (i = 0; i < p; i++)
{
int *a;
a = malloc(sizeof(int));
*a = 0;
pthread_create(&tid[i], NULL, mul, a);
}
for (i = 0; i < p; i++)
pthread_join(tid[i], NULL);
printf("%d", local_sum);
return 0;
}
Let's see:
You want to have p threads, working on the vectors A and B.
You must be aware of that threads share the same memory, and might be interrupted at any time.
You've got p threads, all trying to write to one shared variable local_sum. This leads to unpredictable results since one thread overwrites the value another thread has written there before.
You can bypass this problem by ensuring exclusive access of one single thread to this variable by using a mutex or the like, or you could have one variable per thread, have each thread produce an intermediate result and after joining all threads, collapse all your intermediate results into the final one.
To do this, your main should look something like (assuming your compiler supports a recent C standard):
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define N 2
/* these are variables shared amongst all threads */
int p;
int A[N], B[N];
/* array with one slot per thread to receive the partial result of each thread */
int* partial_sum;
/* prototype of thread function, just to be independent of the place mul will be placed in the source file... */
void *mul(void *arg);
int main (int argc, char** argv)
{
pthread_t* tid;
p = atoi(argv[1]);
const size_t n_by_p = N/p;
if(n_by_p * p != N)
{
fprintf(stderr, "Number of threads must be an integral factor of N\n");
exit(EXIT_FAILURE) ;
}
tid = calloc(p, sizeof(pthread_t));
partial_sum = calloc(p, sizeof(int)) ;
printf("Give Table A\n");
for(size_t i = 0; i < N; ++i)
{
scanf("%d",&A[i]);
}
printf("Give Table B\n");
for(size_t i = 0; i < N; ++i)
{
scanf("%d",&B[i]);
}
for (size_t i =0; i < p; ++i)
{
/* clumsy way to pass a thread it's slot number, but works as a starter... */
int *a;
a = malloc(sizeof(int));
*a = i;
pthread_create(&tid[i], 0, mul, a);
}
for (size_t i = 0; i < p; ++i)
{
pthread_join(tid[i], 0);
}
free(tid);
tid = 0;
int total_sum = 0;
for (size_t i = 0; i < p; ++i)
{
total_sum += partial_sum[i] ;
}
free(partial_sum);
partial_sum = 0;
printf("%d",total_sum);
return EXIT_SUCCESS;
}
Your threaded method mul should now write to its particular partial_sum slot only :
void *mul(void *arg)
{
int slot_num = *(int*)arg;
free(arg);
arg = 0;
const size_t lines = N/p;
const size_t start = slot_num * lines;
const size_t end = start + lines;
partial_sum[slot_num] = 0;
for(size_t i = start; i < end; ++i)
{
partial_sum[slot_num] += A[i]*B[i];
}
return 0;
}
Beware: This code runs smoothly, only if N is some integral multiple of p.
If this condition is not met, due to truncation in N/p, not all elements of the vectors will be processed.
However, fixing these cases is not the core of this question IMHO.
I spared all kinds of error-checking, which you should add, should this code become part of some operational setup...
if (tid=NULL)
-->
if (tid==NULL)
and
for (i=start;i<end;i++)
I suppose we need
for (i=0;i<end-start;i++)
This question already has answers here:
initializing a static variable in header
(4 answers)
Closed 5 years ago.
I'm trying to compare performance of methods about adding two matrix.
one method is just to add.
the other method is to use threads.
but I have a trouble about segmentation error when a thread access a static variable!
Here is my code.
main.c
#include "matrixProcessor.h"
void main()
{
time_t s0, e0;
int i;
int status;
inputVec1 = (int*)malloc(sizeof(int)*(SIZE*SIZE));
inputVec2 = (int*)malloc(sizeof(int)*(SIZE*SIZE));
outputVec = (int*)malloc(sizeof(int)*(SIZE*SIZE));
srand(time(NULL));
initializeVector(inputVec1);
initializeVector(inputVec2);
//printf("=== INPUT VECTOR 1 ===\n");
//printVector(inputVec1);
//printf("=== INPUT VECTOR 1===\n");
//printVector(inputVec2);
//s0 = clock();
//addVec(inputVec1, inputVec2, outputVec);
//e0 = clock();
//printf("Basic Method Time : %f (s)\n",(double)(e0-s0)/CLOCKS_PER_SEC);
s0 = clock();
for(i = 0; i < NUM_THREAD; i++)
{
printf("%d-Thread Call\n",i);
pthread_create(&tid[i], NULL, &addProc, (void*)&i);
sleep(1);
}
e0 = clock();
printf("=== OUTPUT VECTOR===\n");
printVector(outputVec);
printf("Thread Method Time : %f (s)\n",(double)(e0-s0)/CLOCKS_PER_SEC);
free(inputVec1);
free(inputVec2);
free(outputVec);
}
matrixProcessor.c
#include "matrixProcessor.h"
void initializeVector(int* matPtr)
{
int i = 0;
for(i = 0; i < SIZE*SIZE ; i++)
{
matPtr[i] = rand()%100;
}
}
void addVec(int* inputVec1, int* inputVec2, int* outputVec)
{
int i = 0;
for(i = 0; i < SIZE * SIZE; i++)
{
outputVec[i] = inputVec1[i] + inputVec2[i];
}
}
void* addProc(void *p)
{
int* idx = (int*)p;
int count = (SIZE * SIZE) / NUM_THREAD;
int i;
printf("idx value : %d\n",*idx);
printf("Test : %d ", inputVec1[0]);
for(i = (*idx) * count ; i < (*idx)*count + count; i++)
{
outputVec[i] = inputVec1[i] + inputVec2[i];
}
return NULL;
}
void printVector(int* vec)
{
int i = 0;
int j = 0;
for(i = 0; i < SIZE ; i++)
{
for(j = 0; j < SIZE; j++)
{
printf("%d\t", vec[SIZE * i + j]);
}
printf("\n");
}
}
matrixProcessor.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#define SIZE 10
#define NUM_THREAD 10
pthread_t tid[NUM_THREAD];
static int* inputVec1;
static int* inputVec2;
static int* outputVec;
void initializeVector(int* matPtr);
void printVector(int* vec);
void addVec(int* inputVec1, int* inputVec2, int* outputVec);
void* addProc(void *p);
when compiling, i use -static - lpthread options.
I'm sure that accessing static variable cause segmentation error,
because this program prints some messages before reaching a code line which access static variable.
Here is result.
0-Thread Call
idx value : 0
Segmentation Error! ./main
Please someone help me..!
There are multiple problems in your code. The two that jump right out to me are listed below.
First, this one:
pthread_create(&tid[i], NULL, &addProc, (void*)&i);
What's the value of i when the child thread accesses it? It can be anything, because it changes as the main thread spawns more threads and continues to run.
Second, what do you think these free() statements do when they're executed while the child threads are still running:
free(inputVec1);
free(inputVec2);
free(outputVec);
When your code makes those calls, the child threads are still running since you don't call pthread_join() to make sure they've all completed.
You likely get the segmentation violation because your threads are accessing free()'d memory.
I have been working on this program that accomplishes this:
counts the number of occurrences of a specific integer value in a 2D array (matrix). Each position of the matrix must first be initialized to an integer value between 0 and
n. Once initialized, program will search and count the total number of occurrences of a specific value.
The program is run by taking in the parameters as command line arguments:
programName rows cols n c
rows – number of rows of the matrix
cols – number of columns of the matrix
n – the upper bound of the random values of the matrix, values can be 0–(n-1)
c – the value to search for in the matrix, note c must be between 0–(n-1)
After this, the program implements the search using 1 to 10 threads and displays the execution time and number of occurrences.
I seem to have all of this working how I wish, however the problem is that whenever I enter a value over 4 in the command line for rows, I keep getting the segment fault error.
I am at a loss as to what is causing this. Please help me understand what error in my coding may be contributing to this? Thank you.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#define NUM_THREADS 10
int **arr;
int rows, cols, n, c, totalOccurrence, done, numThreads;
int threadCounter[10];
void *matrixThread (void *threadid)
{
long tid;
tid = (long)threadid;
long lowBound = tid * (rows / numThreads);
long highBound = lowBound + (rows / numThreads);
int localcount = 0;
if (tid == numThreads - 1)
{
highBound = rows;
}
long i;
int ic;
for (i = lowBound; i < highBound; i++)
{
for (ic = 0; ic < cols; ic++)
{
if (arr[i][ic] == c)
{
localcount++;
}
}
}
threadCounter[tid] = localcount;
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
if (argc != 5)
{
printf("Error: Invalid number of arguments\n");
}
else
{
rows = strtol(argv[1], NULL, 10);
cols = strtol(argv[2], NULL, 10);
n = strtol(argv[3], NULL, 10);
c = strtol(argv[4], NULL, 10);
int r, cl;
arr = (int**)malloc(rows * sizeof(int));
for (r = 0; r < rows; r++)
{
arr[r] = malloc(cols * sizeof(int));
}
int randomNum;
srand(time(NULL));
for (r = 0; r < rows; r++)
{
for (cl = 0; cl < cols; cl++)
{
randomNum = rand() % n;
arr[r][cl] = randomNum;
}
}
long rc, t;
for (numThreads = 1; numThreads <= 10; numThreads++)
{
struct timeval start,end;
double elapsed_time;
gettimeofday(&start, NULL);
for (t = 0; t < numThreads; t++)
{
rc = pthread_create(&threads[t], NULL, matrixThread, (void *)t);
if (rc)
{
printf ("Error: Thread could not be created; return %d", rc);
exit(-1);
}
}
for (t = 0; t < numThreads; t++)
{
pthread_join(threads[t], NULL);
}
totalOccurrence = 0;
int q;
for (q = 0; q < numThreads; q++)
{
totalOccurrence += threadCounter[q];
}
gettimeofday(&end, NULL);
elapsed_time = (end.tv_sec + end.tv_usec/1000000.10000) - (start.tv_sec + start.tv_usec/1000000.10000);
printf("\nNumber of threads: %d " , numThreads);
printf("Total Occurrences of %d: %d " ,c, totalOccurrence);
printf("Elapsed time: %.8f\n" , elapsed_time);
totalOccurrence = 0;
}
}
pthread_exit(NULL);
}
Here is one problem:
arr = (int**)malloc(rows * sizeof(int));
should be:
arr = (int**)malloc(rows * sizeof(int *));
The allocation of the rows should be like this
arr = (int**)malloc(rows * sizeof(int*));
Because the sizeof datatypes can vary. But the sizeof a pointer will be constant in a particular machine architecture. In a 64 bit machine the sizeof a pointer will be 8 bytes. But sizeof int will be usually 4 bytes (gcc). So here you will be having allocated only 4 blocks. That why when you try to pass more than 4, it's crashing because there's an invalid memory read.
Also your program will cause memory leak, as you are not freeing the allocated memory. Use like this at the end.
for (r = 0; r < rows; r++)
{
free (arr[r]);
}
free (arr);