11

我有此代码用于矩阵乘法,使用 pthreads,但我收到错误“从不同大小的整数转换为指针”

我不知道出了什么问题。我是 pthread 的新手,这就是我到目前为止所做的:

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

这一行的错误:

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

3 回答 3

38

您错误地使用 hack 将整数传递给线程。你所做的背后的想法是一个整数是 4 个字节,一个指针在 x86_32 中是 4 个字节(在 x86_64 中是 8 个字节),所以我可以将整数类型转换为指针类型,然后将其转换回 int 类型而不会丢失任何数据。这适用于大多数情况,但不能保证指针和整数具有相同的大小。C 标准没有规定这一点。

编译器返回一个警告,因为您正在转换一个int可能void *具有不同大小的值,(但实际上在您的机器中它们具有相同的大小)。

您的代码中有一个错误,当您将 int 转换为 void* 调用 pthead_create 函数时,您应该将其转换回整数类型。所以,这条线是错误的:

int *id=(int *)s;

它应该是 :

int id = (int)s; 

考虑这个线程函数的参数为​​零的示例。

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

这是指向地址零的指针。当您尝试尊重它时,您可能会遇到分段错误。

最好的方法是使用intptr_t类型。这种类型在每个体系结构中都具有相同大小的指针(不是 int)。它定义如下:

整数类型,能够保存从 void 指针转换的值,然后转换回具有与原始指针比较相等的值的类型。

所以你可以做这样的事情:

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

(此示例代码取自:如何将整数转换为 void 指针?

但是,不能保证 int 的大小与 的大小相同intptr_t,但是在转换过程中丢失某些数据的可能性确实不大。

编辑

附加错误:

  • float **Aa, **Bb, **Cc;未初始化。
  • start并且end超出了数组的限制。矩阵行未分配在连续的存储区域中。
  • 如果线程函数正在处理矩阵的一块块,则没有必要遍历矩阵 A 和 B 的所有值。您可能只需要内部循环,理论上应该在分配的矩阵部分上工作给它。

我会考虑重写矩阵乘法的代码,因为算法是错误的。

于 2013-10-22T21:10:53.923 回答
3

实现此目的的正确方法是引用变量“i”(检查http://man7.org/linux/man-pages/man3/pthread_create.3.html):

pthread_create(&thread_id[i], NULL, prod, (void *)&i);
于 2015-03-29T15:10:45.437 回答
1

您想要转换整数、短整数或字符并使用 reinterpret_cast() 调用设置指向该值的指针。我们过去只使用 (void*) 值,旧的编译器很高兴,但是新版本,例如 g++ 4.8.5,知道该值不是指针的正确大小。reinterpret_cast 就像一个演员,但它调整了它的大小,所以编译不会抱怨。

例如:

int i = 3;
pointer void * ptr;

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

X11 示例从 addr 中获取一个字符,然后将 XTPOINTER 设置为它。

val = (XTPOINTER)(*(char*)toVal.addr);                   //  warning
val = reinterpret_cast<XTPOINTER>(*(short*)toVal.addr);  // No warning
于 2016-04-15T17:53:02.050 回答