首页 > 解决方案 > 具有posix线程的数组的内积空间

问题描述

我想从用户读取表 A 和 B 作为输入,并从中创建一个内积空间(a1b1+a2b2+……+anbn)并将其保存在 local_sum 中,然后将其共享给 total_sum 变量。我正在做下面的代码,但是有一个段错误。由于某种原因,表 A 和 B 不能传递给函数 MUL。任何帮助都会很棒,谢谢!

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

标签: clinuxpthreads

解决方案


让我们来看看:

你想要有p线程,处理向量AB.

您必须意识到线程共享相同的内存,并且可能随时被中断。

你有p线程,都试图写入一个共享变量local_sum。这会导致不可预知的结果,因为一个线程会覆盖另一个线程之前写入的值。

您可以通过使用互斥锁等确保一个线程对该变量的独占访问来绕过此问题,或者您可以每个线程有一个变量,让每个线程产生一个中间结果,并在加入所有线程后,折叠所有中间结果进入最后一个。

为此,您的 main 应该类似于(假设您的编译器支持最新的 C 标准):

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

您的线程方法mul现在应该只写入其特定的partial_sum插槽:

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

N注意:此代码运行顺利,只有p. 如果不满足此条件,由于 中的截断N/p,不会处理向量的所有元素。但是,解决这些情况并不是这个问题恕我直言的核心。

如果此代码成为某些操作设置的一部分,我没有进行各种错误检查,您应该添加这些检查...


推荐阅读