web-dev-qa-db-fra.com

cast vers le pointeur à partir d'un entier de taille différente, code pthread

J'ai ce code pour la multiplication de matrice, en utilisant pthreads, mais j'obtiens l'erreur "cast to pointeur à partir d'un entier de taille différente"

Je ne sais pas ce qui ne va pas. Je suis novice en lecture, et voici ce que j'ai fait jusqu'à présent:

#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);
}

l'erreur à cette ligne: 

pthread_create(&thread_id[i], NULL, prod, (void *)i); 
7
Ruaa Brkat

Vous utilisez à tort un hack pour passer un entier à un thread. L'idée derrière ce que vous faites est qu'un entier est 4 octets et un pointeur 4 octets en x86_32 (8 octets en x86_64) afin que je puisse convertir un type entier en type pointeur puis le reconvertir en type int sans perdre Les données. Cela fonctionne dans la majorité des scénarios, mais rien ne garantit qu'un pointeur et un entier ont la même taille. La norme C ne spécifie pas ceci pas

Le compilateur renvoie un avertissement parce que vous convertissez une int en void * qui peut avoir une taille différente (mais, en fait, sur votre ordinateur, ils ont la même taille). 

Il y a une erreur dans votre code. Lorsque vous convertissez l'int en un void * appelant la fonction pthead_create, vous devez le reconvertir en un type entier. Donc, cette ligne est fausse: 

int *id=(int *)s;

cA devrait etre : 

int id = (int)s; 

Prenons cet exemple où l'argument de la fonction de thread est zéro. 

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

Ceci est un pointeur sur l'adresse zéro. Lorsque vous essayez de la déférer, vous obtiendrez probablement une erreur de segmentation. 

La meilleure façon de procéder consiste à utiliser le type intptr_t. Ce type a la même taille qu'un pointeur (pas int) dans toutes les architectures. Il est défini comme suit: 

Type entier capable de contenir une valeur convertie à partir d'un pointeur vide et ensuite être reconverti en ce type avec une valeur qui compare égal au pointeur d'origine.

Donc, vous pouvez faire quelque chose comme ça: 

#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);

(Cet exemple de code provient de: Comment convertir un entier en pointeur vide? )

Cependant, rien ne garantit que la taille de int est identique à celle de intptr_t, mais il est très peu probable que certaines données soient perdues lors du processus de conversion. 

MODIFIER 

Erreurs supplémentaires:

  • float **Aa, **Bb, **Cc; ne sont pas initialisés. 
  • start et end dépasse la limite du tableau. Les lignes de la matrice ne sont pas allouées dans des zones de mémoire consécutives. 
  • si la fonction de thread travaille sur une partie de la matrice, il est inutile de passer en revue toutes les valeurs des matrices A et B. Vous voudrez peut-être uniquement la boucle interne qui, en théorie, devrait fonctionner avec la matrice assignée à cela. 

J'envisagerais de réécrire le code pour la multiplication de matrice parce que l'algorithme est faux. 

28
Giuseppe Pes

Pour y parvenir, utilisez la variable "i" (consultez http://man7.org/linux/man-pages/man3/pthread_create.3.html ): 

pthread_create(&thread_id[i], NULL, prod, (void *)&i);
1
ZeZNiQ

Vous souhaitez convertir un entier, un court ou un caractère et définir un pointeur sur cette valeur, utilisez l'appel reinterpret_cast (). Nous avions l'habitude de (void *) la valeur et les anciens compilateurs étaient contents, mais les nouvelles versions, par exemple g ++ 4.8.5, savent que la valeur n'est pas la bonne taille pour un pointeur. reinterpret_cast est comme un casting, mais il a été redimensionné pour que la compilation ne se plaint pas.

Par exemple:

int i = 3;
pointer void * ptr;

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

Exemple X11 qui récupère un caractère dans addr, puis lui attribue XTPOINTER.

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