11

I have this code for matrix multiplication, using pthreads, but I get the error "cast to pointer from integer of different size"

I don't know what is wrong.I am new to pthread, and this is what I have made so far:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>

#define NTHREADS 4

int dim ;
pthread_mutex_t m;       /* Mutex protecting the sum value */
pthread_t thread_id[NTHREADS];  /* Thread ids */
float **A, **B, **C;

void *prod (void *s){
    int *id=(int *)s;
    int idd=*id;


    /* Define local variables */
    int i,j,k, start, end, len ;
    float **Aa, **Bb, **Cc;

    start = dim*idd;       /* Start of this threads slice of the vectors */
    end   = start + dim;      /* End of the slice */


    for (i = 0 ; i < dim; i++)
    {
        for (j = 0;  j < dim; j++)
        {
            Cc[i][j] = 0;
            for (i=start; i<end ; i++) {

                Cc[i][j] += Aa[i][k] * Bb[k][j];
            }
        }
    }
    pthread_mutex_lock (&m);     /* Lock the mutex */
    C[i][j] += Cc[i][j];                /* Update the shared variable */
    pthread_mutex_unlock (&m);   /* Unlock the mutex */

    pthread_exit(NULL);            /* Done! */
}

int main ( int argc, char *argv[] )
{
    void *status;
    float **A, **B, **C;
    int i,j,k;

    if ( argc == 2)
        dim = atoi(argv[1]); // get the dimension of the matrix
    // from the command prompt

    else
        dim = 128;



    A = (float **)malloc(sizeof(float*)*dim);
    B = (float **)malloc(sizeof(float*)*dim);
    C = (float **)malloc(sizeof(float*)*dim);

    for (i = 0 ; i < dim; i++)
    {
        A[i] = (float *)malloc(sizeof(float)*dim);
        B[i] = (float *)malloc(sizeof(float)*dim);
        C[i] = (float *)malloc(sizeof(float)*dim);
    }

    for (i=0; i<dim; i++)
    {
        for (j = 0 ; j < dim; j++)
        {
            A[i][j]=rand();
            B[i][j]=rand();
        }
    }

    struct timeval t1, t2;
    gettimeofday(&t1, NULL);

    // you need to parallelize this
    // perform the multiplication
    for(i=0;i<NTHREADS;i++) {

        pthread_create(&thread_id[i], NULL, prod, (void *)i);
    }
    /* Wait on the other threads */
    for(i=0;i<NTHREADS;i++) {
        pthread_join(thread_id[i], &status);
    }

    gettimeofday(&t2, NULL);

    double t = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec ) / 1000000.0;
    // take the difference and report it in seconds
    printf("execution time %f seconds\n",t);
}

the error at this line:

pthread_create(&thread_id[i], NULL, prod, (void *)i); 
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
Ruaa Brkat
  • 151
  • 1
  • 2
  • 14
  • 3
    Please consider formatting your code and referencing the line number giving you this error. – Alexander L. Belikoff Oct 22 '13 at 20:46
  • Duplicate of: http://stackoverflow.com/questions/8487380/how-to-cast-an-integer-to-void-pointer (but ignore the accepted answer there as it is wrong, look at the other answers). – interjay Oct 22 '13 at 20:52
  • `i` is an int. You're casting it to a `void*`. Doesn't that seem like a bad idea? – Hot Licks Oct 22 '13 at 20:53
  • @HotLicks I changed the sentence to pthread_create(&thread_id[i], NULL, prod, &thread_id[i]); but I get this error: "Segmentation fault (core dumped)" – Ruaa Brkat Oct 22 '13 at 20:55
  • That's not an error, but a warning. Are you using any particular compilation option? – Giuseppe Pes Oct 22 '13 at 20:59
  • @GiuseppePes I don't know what do you mean but when I run my code I just type :gcc -pthread -o test test.c – Ruaa Brkat Oct 22 '13 at 21:04
  • shall we ignore the blatant use of the indeterminate pointers `Aa`, `Bb`, and `Cc` in the posted thread proc? it has nothing to do with your question, but if you expect this to work once that question is resolved, reconsider that thought. – WhozCraig Oct 22 '13 at 21:34
  • @WhozCraig thank you, I will. but I am getting this error now: Segmentation fault (core dumped) – Ruaa Brkat Oct 22 '13 at 21:36
  • @user2908749 Did you even *read* the comment you just thanked me for? – WhozCraig Oct 22 '13 at 21:39
  • @WhozCraig I used them as local variables to avoid false sharing, and yes I read your comment – Ruaa Brkat Oct 22 '13 at 21:44
  • After fixing that issue, make sure your compiling with debugging info enabled (-g), and run your program under gdb. I can all-but-guarantee you it will tell you exactly what is blowing up your efforts. And in parting I'll point out one more bug: you never initialize your global mutex `m`. – WhozCraig Oct 22 '13 at 21:46
  • we don't initialize the mutex!!! – Ruaa Brkat Oct 22 '13 at 21:55
  • @user2908749 then *we get segmentation faults!!!*. You also don't initialize `k`, yet you use it for an index (into your uninitialized pointer arrays, so I suppose thats only appropriate), and `len` is not even used at all. Looking at it now, with the exception of the local variable *declarations* and the actual usage of the loop variables themselves, there isn't *any* code in your thread proc that is *defined* behavior. – WhozCraig Oct 22 '13 at 21:57
  • I removed _len_ and added another for loop for the variable k; what do you mean by this:"there isn't any code in your thread proc that is defined behavior." – Ruaa Brkat Oct 22 '13 at 22:06

3 Answers3

42

You are wrongly using an hack to pass an integer to a thread. The idea behind what you are doing is an integer is 4 bytes and a pointer is 4 bytes in x86_32 (8 bytes in x86_64) so I can convert an integer type to a pointer type and then convert it back to an int type without losing any data. This works in the majority of the scenarios, but there is not guarantee that a pointer and an integer have the same size. The C standard does not specify this.

The compiler returns a warning because you are converting an int to void * which may have different size, ( but in fact in your machine they have the same size).

There is a error in you code, when you convert the int to a void* calling the pthead_create function, you should convert it back to an integer type. So, this line is wrong :

int *id=(int *)s;

it should be :

int id = (int)s; 

Consider this example where the argument for the thread function is zero.

s=0; therefore  ---> *id=(int*)0; // Null pointer 

This is a pointer to the address zero. When you try to deference it, you will likely get an segmentation fault.

The best way to do this is by using the intptr_t type. This type has the same size of a pointer (not int) in every architecture. It is defined as follows :

Integer type capable of holding a value converted from a void pointer and then be converted back to that type with a value that compares equal to the original pointer.

So you can do something like this:

#include <stdint.h>

void *threadfunc(void *param)
{
    int id = (intptr_t) param;
    ...
}

int i, r;
r = pthread_create(&thread, NULL, threadfunc, (void *) (intptr_t) i);

(This example code has been taken from : How to cast an integer to void pointer?)

However, there is not guarantee that the size of int is the same of the size of intptr_t, but it's really unlikely that some data is lost in the conversion process.

EDIT

Additional errors :

  • float **Aa, **Bb, **Cc; are not initialised.
  • start and end exceeds the limit of the array. The matrix rows are not allocated in consecutive memory areas.
  • if the thread function is working on a chunks of the matrix, there is not point to go through all the values of the matrix A and B. You might want only the internal loop which, in theory, should work on the part of matrix assigned to it.

I would consider to rewrite the code for the matrix multiplication because the algorithm is wrong.

Community
  • 1
  • 1
Giuseppe Pes
  • 7,772
  • 3
  • 52
  • 90
  • Are you sure it's an error and not a warning? Because compiling you code I have got a warning. – Giuseppe Pes Oct 22 '13 at 21:18
  • oh sorry, it is a warning, but still when I execute the code I get:Segmentation fault (core dumped) – Ruaa Brkat Oct 22 '13 at 21:20
  • 1
    @user2908749 Someone can, that someone may be you. Consider what you're passing to your thread proc (an promoted `int` value cast to a pointer), then consider what you're *doing* with that *non-addressable* pointer value in the first two lines of your thread procedure. then consider my post in general comment above. You're using uninitialized pointers *rampantly* in your thread procedure. And the latter has *nothing* to do with your original question. Giuseppe's answer to the question you *posted* is correct, and should at least be up-voted – WhozCraig Oct 22 '13 at 21:37
  • Yes, this is not a pthreads issue, it's just massively, massively wrong C all the way down. – Crowman Oct 22 '13 at 22:43
4

Correct way to achieve this is by referencing the variable "i" (check http://man7.org/linux/man-pages/man3/pthread_create.3.html):

pthread_create(&thread_id[i], NULL, prod, (void *)&i);
hichris123
  • 10,145
  • 15
  • 56
  • 70
ZeZNiQ
  • 612
  • 7
  • 14
  • 1
    However if 'i' changes then all the threads have a pointer to the same version. In the above example it's likely 'i' is the index into the thread_id array. The threads won't necessarily read their own index value since it might have been incremented before the thread starts to execute. You'd need an array of integers the same size as the thread_id array, populate it with the indexes and pass a pointer to that integer in instead. – steveayre Mar 24 '16 at 14:19
  • 1
    I agree that this is not the ideal way to do this, however, its not incorrect either. Just wanted to provide a quick fix for the OP's issue for passing a unique arg (in this case the value of i) per thread, which isn't incorrect. – ZeZNiQ May 26 '19 at 15:27
1

You want to cast integer, short, or char and set a pointer to that value use the reinterpret_cast() call. We used to just (void*) the value and the older compilers were happy, but the new versions, for example g++ 4.8.5, know the value is not the right size for a pointer. reinterpret_cast is just like a cast but it resized it so the compile doesn't complain.

For example:

int i = 3;
pointer void * ptr;

ptr = (void*)i;                    // will generate the warning
ptr = reinterpret_cast<void*>(i);  // No warning is generated

X11 example getting a character out of addr and then setting XTPOINTER to it.

val = (XTPOINTER)(*(char*)toVal.addr);                   //  warning
val = reinterpret_cast<XTPOINTER>(*(short*)toVal.addr);  // No warning
user3416126
  • 148
  • 11