I have a project to illustrate how to use shared memory in C. And this is my suggested assignment for my project this semester: adding up all elements in a 2d array, in a special way:
take input from user the row size (m) and column size (n), for example m = 4, n = 3.
the program will be called, for example: myadder 9 8 7 3 2 1 2 3 4 2 10 12 (these 12 numbers input are separated by white-space or return key)
create a shared memory 1d array of enough size to hold the entire above 2d array
then, create a shared memory 1d array of the size of the number of rows m. This array will be used to store the totals of each of the rows after it is calculated
the program then fork off a child process for each row in the array. This child process will total up its associated row and only it's row from shared memory, and store result in its associated element in another 1d array, called total_row
The parent process will wait until all children have finished, then add up all elements in total_row.
Can you give me hints to finish the above task?
I believe this should do the trick:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
int main ()
{
int w, h, i, j;
/* Read the width and height */
scanf ("%d %d", &w, &h);
/* Create and read the entire array */
int *arr = malloc (w * h * sizeof (int));
for (i = 0; i < w * h; ++i)
scanf ("%d", &arr[i]);
/* Obtain a shared memory segment with the key 42 */
int shm = shmget (42, h * sizeof (int), IPC_CREAT | 0666);
if (shm < 0)
{
perror ("shmget");
return 1;
}
/* Attach the segment as an int array */
int *row = shmat (shm, NULL, 0);
if (row < (int *) NULL)
{
perror ("shmat");
return 1;
}
for (i = 0; i < h; ++i)
/* Create h children and make them work */
if (!fork ())
{
for (j = row[i] = 0; j < w; ++j)
row[i] += arr[i * w + j];
return 0;
}
/* Wait for the children to finish up */
for (i = 0; i < h; ++i)
wait (&j);
/* Sum the row totals */
for (i = j = 0; i < h; ++i)
j += row[i];
printf ("%d\n", j);
/* Detach the shared memory segment and delete its key for later reuse */
shmdt (row);
shmctl (shm, IPC_RMID, NULL);
free (arr);
return 0;
}
Consider the following array declaration:
int arr[8];
What happens in memory when we make this declaration?
32 bytes are immediately reserved in memory, 4 bytes each for the 8 integers. Since the array is not being initialized, all 8 values present in it would be garbage values.
This happens because
the storage class of this array is assumed to be AUTO. If the storage class is declared to be STATIC, then all of the array elements would have a default initial value of 0.
Whatever be the initial values, all of the array elements would always be present in contiguous memory locations.
This arrangement of array elements in memory is shown in fig.
12 34 66 -45 23 346 77 90
65508 65512 65516 65520 65524 65528 65532 65536
This below code uses 2 shared memory segments..
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define KEY_2D 12345
#define KEY_ROW 54321
int main(int argc, char **argv) {
int rows, cols;
scanf("%d %d", &rows, &cols);
if(rows <= 0 || cols <= 0) {
printf("invalid input\n");
return 1;
}
int *dataa_user = NULL; /* To get user input for 2D array */
int i = 0;
int shm_2d = -1;
dataa_user = (int *) malloc(rows * cols * sizeof(int));
/* Do you need to take input from user as 2D array? and then
* convert it back to 1D array?
* I wonder as this is probably your assignment to understand
* some C and Unix concepts
*/
for(i = 0; i < rows * cols; i ++)
scanf("%d", &dataa_user[i]);
/* Creating shared memory that holds 2D array as 1D array */
shm_2d = shmget(KEY_2D, rows * cols * sizeof (int), IPC_CREAT | 0666);
if(shm_2d < 0) {
perror("shmget");
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
/* Attach to the shared memory */
void *data_2d = shmat(shm_2d, NULL, 0);
if(data_2d == (void *)-1) {
perror("shmat");
shmctl (shm_2d, IPC_RMID, NULL);
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
int shm_row = -1;
/* Copy the 1D array to shared memory */
memcpy( data_2d, dataa_user, rows * cols * sizeof(int));
free(dataa_user);
dataa_user = NULL;
/* Creating shared memory to keep the sum of each row as 1D array */
shm_row = shmget(KEY_ROW, rows * sizeof (int), IPC_CREAT | 0666);
if(shm_row < 0) {
perror("shmget");
shmdt(data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
return 1;
} /* this closing brace was missed when i posted it first time.. */
/* Attach to the shared memory */
void *data_row = shmat(shm_row, NULL, 0);
if(data_row == (void *)-1) {
perror("shmat");
shmdt (data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 1;
}
/* Initialize it to 0. */
memset(data_row, 0, rows * sizeof(int));
for(i = 0; i < rows; i ++) {
if(!fork()) {
int k = 0;
int *dataa_2d = (int *)data_2d;
int *total_row = (int *)data_row;
for(; k < cols; k ++)
total_row[i] += dataa_2d[i * cols + k]; //add data to shm[row index] for each col in that row
return 0;
}
}
int sts = 0;
for(i = 0; i < rows; i ++) {
wait(&sts); /* wait for all the children to exit. */
}
int total_2d = 0;
int *total_row = (int *)data_row;
for(i = 0; i < rows; i ++) {
total_2d += total_row[i]; /* main process adding up all the row sum values */
}
printf("%d\n", total_2d);
/* clean up of IPC(shms used) */
shmdt(data_2d);
shmdt(data_row);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 0;
}
Your problem statement only mandates use of fork() system call.. So, the problem as such is simple (taking advantage of COW)..
(If you were supposed to use exec() system calls, then it might help you understand the reality in linux systems.. Also if totalling of total_row was assigned to each child process, like summing up to 3rd shared memory or something, it would have helped in understanding synchronization.. )
Anyway, hope this helps..
Related
I really can't see an issue, but then again, I just started learning C a few weeks ago, as a way to get faster code than what I was using.My guess is it has to do with my memory allocation. This is small, but eventually I will be using this process with Count values up to 25.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int i;
int j;
int Count = 2; /* set number of bits */
int Combos = pow(2,Count); /* calculate count of all 6 bit binary numbers */
int SIZE = (Combos + 1) * (Count + 1); /* calculate number of array elements */
/* rows * columns */
/* rows = Combos + 1 */
/* columns = count +1 (row number + bits)*/
/* 0th spot will hold row number */
printf("SIZE = %d\n", SIZE); /* print number of array elements */
int (*a)[Count + 1] = malloc(SIZE); /* allocate memory for array based on size of */
/* int variable times SIZE */
/* (SIZE) is number of elements */
if (a == NULL) /* if not enough memory, print error message */
{
fprintf(stderr,"Could not allocate that much memory");
return 1;
}
/* do something with array */
for (i =0; i<= Combos; i++){
a[i][0] = i; /* set 0th element of this row to row number */
printf("a[%d][0] = %d ", i,a[i][0]); /* print 0th element of this row */
for (j =1; j<= Count; j++){ /* print the rest of the elements in this row */
a[i][j] = 1;
printf("a[%d][%d] = %d ", i,j,a[i][j]);
} /* end j loop */
printf("\n"); /* line feed */
} /* end i loop */
free(a); /* release memory allocated for array */
return 0;
}
Note that malloc(K) allocates K bytes of memory.
If you'd like to allocate an array consisting of N elements of type T, you need to call malloc(N * sizeof(T)).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const size_t COUNT = 30;
const size_t COMBOS = (size_t)1 << COUNT;
const size_t SIZE = (COMBOS + 1) * (COUNT + 1);
printf("SIZE = %zu\n", SIZE);
int (*a)[COUNT + 1] = malloc(SIZE * sizeof(int));
if (a == NULL)
{
fprintf(stderr, "Could not allocate that much memory\n");
return 1;
}
for (i = 0; i <= COMBOS; i++)
{
a[i][0] = i;
printf("a[%d][0] = %d%s", i, a[i][0], " ");
for (j = 1; j <= COUNT; j++)
{
a[i][j] = 1;
printf("a[%d][%d] = %d%s", i, j, a[i][j], (j == COUNT ? "\n" : " "));
}
}
free(a);
return 0;
}
Trying to allocate 2d array in shared memory. Execution returns segmentation fault during assignments (I think). Should I do the assignments in another way? This is my code:
...
#define KEYSM 46378
#define X 10
#define Y 10
int main(){
int i, j;
int shm_id;
int **addressArray;
if((shm_id = shmget(KEYSM, sizeof(int[X][Y]), IPC_CREAT | 0666)) == -1){
perror("shmget");
exit(-1);
}
if((addressArray = (int **)shmat(shm_id, NULL, 0)) == (int **)-1){
perror("shmat");
exit(-1);
}
for(i = 0; i < X; i++){
for(j = 0; j < Y; j++){
if(i % 2 != 0)
addressArray[i][j] = -1;
else
addressArray[i][j] = 0;
}
}
...
}
Your problem is in a – (your ?) – misunderstanding of the difference of a true 2D array, and a pointer→pointer→value indirection.
When you define a int **a this is interpreted as a pointer to another pointer, that then reference an int. Assigning a pointer obtained from an allocation function like malloc or shmat to such a double pointer, then as far as the semantics of C go, it expects this allocation of memory contain further pointers. So if you do a double dereference, and there's not a valid pointer there, it will fall flat on its face.
This misunderstanding is furthered by the fact, that in C you can validly write int a[X][Y]; and dereference it with a[i][j]. The key insight to understand this is, that the first "half", i.e. that with a array defined like that, a[i]… decays into a int* pointer, that points toward the 0th element in the i "column". The other half …[j] then dereferences this implicitly "appearing" pointer.
Multidimensional arrays in C are deceiving and I strongly discourage using them like that. Also you'll have a hard time to properly implement specific padding and row alignments with them, without jumping some really annoying arithmetic.
It's easier by far, to just write down the calculations explicitly, with the added benefit of having precise control of padding and alignment.
Suppose we want to create a 2D array of int, that shall be aligned to the sizes of long long
size_t const array_height = ...;
size_t const array_width = ...;
size_t const alignment = sizeof(long long);
size_t const row_size = array_width * sizeof(int);
size_t const row_stride =
alignment * ((row_size + alignment-1) / alignment);
size_t const array_size = array_height * row_stride;
int const shm_id = shmget(KEYSM, array_size, IPC_CREAT | 0666);
if( 0 > shm_id ){
perror("shmget");
exit(-1);
}
int *const array = shmat(shm_id, NULL, 0);
if( (void*)-1 == array ){
perror("shmat");
exit(-1);
}
for(size_t j = 0; j < array_height; ++j){
int *const row = array + j * row_stride;
for(size_t i = 0; i < array_width; ++i){
row[i] = (i % 2) ? -1 : 0;
}
}
A segfault is a runtime error, but your code shouldn't even compile, look a this statement (paranthesis missing):
if ( ( addressArray = ( int** ) shmat ( shm_id, NULL, 0 ) == ( int** ) -1 )
And what if that assignment failed? Does perror terminate the process? No. But you still access the array below. Most likely the source of the seg fault.
As mch pointed out:
// i is not declared
for(i = 0; i < X; i++){
// j is not declared, after j < Y, use semicolon instead of comma
for(j = 0; j < Y, j++){
// if the result is not zero you're doing an assignment
if(i % 2 != 0)
addressArray[i][j] = -1;
// but immediately after you assign a zero,
// previous statement -> useless
// 'else' is missing here
addressArray[i][j] = 0;
}
}
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.
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);
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);