【问题标题】:pthread_create() fails (invalid argument) every 60 threads on Xeon PhiXeon Phi 上每 60 个线程 pthread_create() 失败(参数无效)
【发布时间】:2014-11-13 07:45:57
【问题描述】:

我有一段 pthread 代码在这里列为函数“thread”。它基本上创建了许多线程(通常在 Xeon Phi 上为 240 个,在 CPU 上为 16 个)然后加入它们。

如果我只调用这个 thread() 一次,它在 CPU 和 Xeon Phi 上都能完美运行。如果我再调用一次,它在 CPU 上仍然可以正常工作,但 pthread_create() 将报告“错误 22”,这应该是每 60 个线程的“无效参数”。

例如,线程 0、线程 60、线程 120 等线程()的第 2 次运行(也是进程中创建的 241、301、361 等线程)将失败(错误 22)。但线程 1~59、61~119、121~240 等工作完美。

请注意,此问题仅在 Xeon Phi 上发生。

我已经检查了堆栈大小和参数本身,但我没有找到原因。论据是正确的。

void thread()
{

...

int i, rv;
cpu_set_t set;
arg_t args[nthreads];
pthread_t tid[nthreads];
pthread_attr_t attr;
pthread_barrier_t barrier;

rv = pthread_barrier_init(&barrier, NULL, nthreads);
if(rv != 0)
{
    printf("Couldn't create the barrier\n");
    exit(EXIT_FAILURE);
}

pthread_attr_init(&attr);

for(i = 0; i < nthreads; i++)
{
    int cpu_idx = get_cpu_id(i,nthreads);

    DEBUGMSG(1, "Assigning thread-%d to CPU-%d\n", i, cpu_idx);

    CPU_ZERO(&set);
    CPU_SET(cpu_idx, &set);
    pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &set);

    args[i].tid = i;
    args[i].ht = ht;
    args[i].barrier = &barrier;

    /* assing part of the relR for next thread */
    args[i].relR.num_tuples = (i == (nthreads-1)) ? numR : numRthr;
    args[i].relR.tuples = relR->tuples + numRthr * i;
    numR -= numRthr;

    /* assing part of the relS for next thread */
    args[i].relS.num_tuples = (i == (nthreads-1)) ? numS : numSthr;
    args[i].relS.tuples = relS->tuples + numSthr * i;

    numS -= numSthr;

    rv = pthread_create(&tid[i], &attr, npo_thread, (void*)&args[i]);
    if (rv)
    {
        printf("ERROR; return code from pthread_create() is %d\n", rv);
        printf ("%d %s\n", args[i].tid, strerror(rv));
        //exit(-1);
    }

}

for(i = 0; i < nthreads; i++)
{
    pthread_join(tid[i], NULL);
    /* sum up results */
    result += args[i].num_results;
}
}

【问题讨论】:

  • 什么是nthreads?如何创建 tidargs 数组?一个完整的测试用例的机会吗?
  • @MikeSeymour nthreads 是线程数。当报告的问题发生在 Xeon Phi 上时,它是 240。我添加了 tid 和 args 的声明。
  • 给我们一个可以编译的完整程序。
  • 我正在查看 scatter_threads.h 中的 get_cpu_id,当 frontback 溢出时,它看起来会返回随机垃圾。此外,由于该函数的行为受到值为“60”的魔术常数的影响,并且在达到 60 次调用该函数时遇到问题,我怀疑它不是“一切都好”。
  • balanced_threads.h 中的get_cpu_id 也是如此。它不会检查mfree 的溢出,并且会在发生这种情况时开始读取、覆盖和返回随机内容。我会开始研究这些功能。也许setaffinity_np 不会检查 cpu_set 中设置的太高位,并且在使用虚假属性调用 pthread_create 之前不会检测到该错误。

标签: c++ c multithreading pthreads xeon-phi


【解决方案1】:

这里有一个最小的例子来重现您的问题并显示您的代码最有可能出错的地方:

#define _GNU_SOURCE
#include <pthread.h>
#include <err.h>
#include <stdio.h>

void *
foo(void *v)
{
        printf("foo\n");
        return NULL;
}

int
main(int argc, char **argv)
{
        pthread_attr_t attr;
        pthread_t thr;
        cpu_set_t set;
        void *v;
        int e;

        if (pthread_attr_init(&attr))
                err(1, "pthread_attr_init");
        CPU_ZERO(&set);
        CPU_SET(255, &set);
        if (pthread_attr_setaffinity_np(&attr, sizeof(set), &set))
                err(1, "pthread_attr_setaffinity_np");

        if ((e = pthread_create(&thr, &attr, foo, NULL)))
                errx(1, "pthread_create: %d", e);

        if (pthread_join(thr, &v))
                err(1, "pthread_join");
        return 0;
}

正如我在 cmets 中对您的问题所推测的那样,pthread_attr_setaffinity_np 不会检查 cpu 集是否正常。相反,该错误被pthread_create 捕获。由于您在 github 上的代码中的 cpu_get_id 函数显然已损坏,因此我将开始寻找问题所在。

在 Linux 上测试过,但 pthread_attr_setaffinity_np 就是从那里来的,所以这可能是一个安全的假设。

【讨论】:

  • 非常感谢!那就是问题所在!我重写了调度程序部分,现在可以了!谢谢。
  • 附注除非您仔细查看,否则您对 Xeon Phi 上哪些逻辑 CPU 彼此靠近的假设可能是错误的。从逻辑CPU到硬件的映射与“普通”至强上的映射相同(这本身就够反常了:-))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多