【问题标题】:Writing to one array from multiple threads从多个线程写入一个数组
【发布时间】:2017-05-16 12:23:23
【问题描述】:

我正在学习 pthreads。

现在我正在尝试使用多个pthreads 编写写入一个二维array 的程序。每个pthread 只负责array 的一行。所以那里没有种族或重叠。 目标是在不使用全局变量的情况下使其尽可能快。

我实施的第一个解决方案是使用global variable 的解决方案。它按预期工作。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int **array;
const int NTHREADS = 5;
const int ELEMENTS = 3;

void *worker(void *arg);
void print_array(int **array);

int main()
{
    int i, j;
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));

    array = (int**)malloc(sizeof(int*));
    for(i = -1; i < NTHREADS; i++)
    {
        array[i] = (int*)malloc(sizeof(int));
        for (j = -1; j < ELEMENTS; j++)
        {
            array[i][j] = (int)malloc(sizeof(int));
        }
    }

    for (i = 0; i < NTHREADS; i++)
        pthread_create(&threads[i], NULL, worker, (void*)i);

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(array);
    return 0;
}

void *worker(void *arg)
{
    int tid = (int)arg;

    for (int j = 0; j < ELEMENTS; j++)
        array[tid][j] = j;
    return (NULL);
}

void print_array(int **array)
{
    for (int i = 0; i < NTHREADS; i++)
    {
        for (int j = 0; j < ELEMENTS; j++)
            printf("%d,", array[i][j]);

        printf("\n");
    }
}

然后我使用struct 而不是global variable 编写了相同的程序。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

const int NTHREADS = 5;
const int ELEMENTS = 3;

typedef struct          s_asd
{
    int                 **array;
    int                 tid;
}                       t_asd;

void *worker(void *arg);
void print_array(int **array);

int main()
{
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
    t_asd tmp;
    int i, j;

    tmp.array = (int**)malloc(sizeof(int*));
    for (i = 0; i <= NTHREADS; i++)
    {
        tmp.array[i] = (int*)malloc(sizeof(int));
        for (j = 0; j <= ELEMENTS; j++)
            tmp.array[i][j] = (int)malloc(sizeof(int));
    }

    for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++)
        pthread_create(&threads[tmp.tid], NULL, worker, &tmp);

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(tmp.array);
    return 0;
}

void *worker(void *arg)
{
    t_asd   *tmp = (t_asd*)arg;

    for (int j = 0; j < ELEMENTS; j++)
        tmp->array[tmp->tid][j] = j;
    return (NULL);
}

void print_array(int **array)
{
    for (int i = 0; i < NTHREADS; i++)
    {
        for (int j = 0; j < ELEMENTS; j++)
            printf("%d,", array[i][j]);

        printf("\n");
    }
}

这个,打印随机数。我知道我在所有线程中使用相同的指针,但线程本身并没有使用相同的内存区域。那么为什么它会打印随机数呢? 不使用全局变量的最佳解决方案是什么?

更新 1。 第二个程序的输出:

-1413467520,32668,-1413467440,
-1413467584,-1413467568,-1413467552,
-1413467504,-1413467488,-1413467472,
0,1,2,
0,1,2,

【问题讨论】:

  • 你能显示输出吗?
  • 你应该使用互斥锁来避免并发访问。
  • 你对 malloc 的使用是错误的。 array = (int**)malloc(sizeof(int*)); 只为一个指针分配空间。
  • @ShellCode 我用第二个程序的输出更新了这个问题。输出本身可能会有所不同。而且垃圾值会在不同的地方。
  • 所有这些 malloc 都非常错误One never casts the return value of malloc in C - 在你的情况下,(int)malloc(sizeof(int)) 中的演员掩盖了一个 valid 警告/错误。

标签: c arrays multithreading pthreads


【解决方案1】:

尝试类似的方法:

int main()
{
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
    t_asd tmp;
    int i, j;

    tmp.array = (int**)malloc(NTHREADS * sizeof(int*));
    for (i = 0; i <= NTHREADS; i++)
    {
        tmp.array[i] = (int*)malloc(ELEMENTS * sizeof(int));

        //can be deleted if you want
        for (j = 0; j <= ELEMENTS; j++)
            tmp.array[i][j] = 0;
    }

    for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++) {
        t_asd *arg = (t_asd *) malloc(sizeof(t_asd));
        memcpy(arg, &tmp, sizeof(t_asd)); //will copy the current tid and the pointer to the array in a new memory area
        pthread_create(&threads[tmp.tid], NULL, worker, arg);
    }

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(tmp.array);
    return 0;
}

当然这是一个例子,你必须释放所有的分配

【讨论】:

  • 此代码有效。如果我理解正确,这与 Andriy Berestovskyy 建议的方法基本相同,只是实现方式不同?但我有一个问题。如果tmp 不是堆栈分配的结构,则将动态分配指向结构的指针。而且会很大。 (包含一堆指针和变量) memcpy 会需要很长时间来复制吗?
  • 是的,Andriy 和我建议的想法相同。我很确定 memset 的复杂度永远不会超过 O(n) 但我认为您不必担心这一点,因为您只是在复制指针,而不是所有数据
  • 非常感谢。将尝试这种实现,带有分形渲染。准备好时会报告。 :) 现在,我会将这个问题标记为已回答。
【解决方案2】:

您将局部变量 tmp 作为参数传递给线程并同时在循环中更改它。这是一场数据竞赛,您的线程很可能会处理相同的数据。

将tmp转换为数组,填充对应的元素并将其传递给对应的线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多