pthread从共享内存中读取

时间:2011-06-07 15:19:10

标签: c cuda pthreads

来自CUDA我对如何从线程读取共享内存感兴趣,并与CUDA的读取对齐要求进行比较。我将使用以下代码作为示例:

#include <sys/unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define THREADS 2

void * threadFun(void * args);

typedef struct {
    float * dataPtr;
    int tIdx,
    dSize;
} t_data;

int main(int argc, char * argv[])
{
    int i,
    sizeData=5;
    void * status;

    float *data;

    t_data * d;

    pthread_t * threads;
    pthread_attr_t attr;

    data=(float *) malloc(sizeof(float) * sizeData );
    threads=(pthread_t *)malloc(sizeof(pthread_t)*THREADS);
    d = (t_data *) malloc (sizeof(t_data)*THREADS);

    data[0]=0.0;
    data[1]=0.1;
    data[2]=0.2;
    data[3]=0.3;
    data[4]=0.4;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for (i=0; i<THREADS;i++)
    {
        d[i].tIdx=i;
        d[i].dataPtr=data;
        d[i].dSize=sizeData;
        pthread_create(&threads[i],NULL,threadFun,(void *)(d+i));
    }

    for (i=0; i<THREADS; i++)
    {
        pthread_join(threads[i],&status);
        if(status);
            //Error;
    }
    return 0;
}

void * threadFun(void * args)
{
    int i;

    t_data * d= (t_data *) args;

    float sumVal=0.0;

    for (i=0; i<d->dSize; i++)
        sumVal+=d->dataPtr[i]*(d->tIdx+1);

    printf("Thread %d calculated the value as %-11.11f\n",d->tIdx,sumVal);

    return(NULL);
}

在threadFun中,整个指针d指向共享内存空间(我相信)。从我在文档中遇到的从多个线程读取是可以的。在CUDA中,需要合并读取 - pthreads中是否存在类似的对齐限制?即如果我有两个线程从相同的共享地址读取我假设某个地方沿线,调度程序必须将一个线程放在另一个线程之前。在CUDA中,这可能是一项代价高昂的操作,应该避免。从共享内存中“同时”读取是否会受到惩罚 - 如果是这样,那么它可以忽略不计?即两个线程可能需要同时读取d-&gt; datPtr [0] - 我假设内存读取不能同时发生 - 这个假设是错误的吗?

另外,我读了一个article from intel,说在多线程时使用数组结构 - 这与cuda一致。如果我这样做,我几乎不可避免地需要线程ID - 我认为这将要求我使用互斥锁定线程ID,直到它被读入线程的范围,这是真的还是会有其他方式识别线程?

关于多线程程序的内存管理的文章也将受到赞赏。

4 个答案:

答案 0 :(得分:2)

当您的线程数据指针d指向共享内存空间时,除非您将该指针递增以尝试读取或写入共享内存空间数组中的相邻线程数据元素,否则基本上处理本地化的线程数据。此外,args的值对于每个线程都是本地的,所以在这两种情况下,如果你没有递增数据指针本身(即,你永远不会调用类似d++等的东西,那么你'重新指向另一个线程的内存),不需要互斥锁来保护“属于”你线程的内存。

同样对于你的线程ID,因为你只是从产生线程写入该值,然后在实际生成的线程中读取该值,所以不需要互斥或同步机制......你只需要数据的单个生产者/消费者。只有在有多个线程可以读写相同的数据位置时,才需要互斥锁和其他同步机制。

答案 1 :(得分:1)

CPU有缓存。读取来自缓存,因此每个CPU /核心都可以从自己的缓存中读取,只要相应的缓存行是SHARED即可。将强制缓存行写入EXCLUSIVE状态,使其他CPU上的相应缓存行无效。

如果你有一个每个线程都有一个成员的数组,并且对该数组都有读写操作,你可能希望将每个成员与一个高速缓存行对齐,以避免错误共享。

答案 2 :(得分:0)

  1. 内存读取到同一区域的同一区域到同一内存不是共享内存系统中的问题(写入是另一回事,相关区域是缓存行:64-256字节,具体取决于系统)

  2. 我没有看到任何使得thread_id成为同步操作的原因。 (并且您可以使用对您有意义的任何ID来提供您的线程,它可以比从抽象ID中获取有意义的值更简单)

答案 3 :(得分:0)

来自CUDA可能让你认为复杂。 POSIX线程更简单。基本上你正在做的事情应该有效,只要你只是在共享数组中阅读。

另外,不要忘记CUDA是C ++的肢解而不是C,所以有些事情也可能与这个方面不同。例如,在你的代码中,从malloc转换回来的习惯通常是真正的C程序员所不喜欢的,因为它可能是微妙错误的根源。