0

我编写了一个简单的测试程序来产生一些处理器负载。它将抛出 6 个线程并在每个线程 pi 中进行计算。但是处理器在目标平台(arm)上只生成 3 个线程,普通 Linux-PC 上的同一个程序会生成全部 6 个线程。

问题是什么?

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

#define ITERATIONS 10000000000000
#define NUM_THREADS 6

void *calculate_pi(void *threadID) {
        double i;
        double pi;
        int add = 0;

        pi = 4;
        for (i = 0; i < ITERATIONS; i++) {
                if (add == 1) {
                        pi = pi + (4/(3+i*2));
                        add = 0;
                } else {
                        pi = pi - (4/(3+i*2));
                        add = 1;
                }
        }

        printf("pi from thread %d = %20lf in %20lf iterations\n", (int)threadID, pi, i);

        pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
        pthread_t threads[NUM_THREADS];
        int rc;
        int i;

        for ( i = 0 ; i < NUM_THREADS; i++) {
                rc = pthread_create(&threads[i], NULL, calculate_pi, (void *)i);
                if (rc) {
                        printf("ERROR; return code from pthread_create() is %d\n", rc);
                        exit(EXIT_FAILURE);
                }
        }

        for ( i = 0 ; i < NUM_THREADS; i++) {
                pthread_join(threads[i], NULL);
        }

        return(EXIT_SUCCESS);
}
4

4 回答 4

1

如果目的只是加载处理器,并且您有一个支持 OpenMP 的编译器,则可以使用以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <omp.h>

double calculate_pi(int iterations) {

  double pi;
  int add = 0;

  pi = 4;
  for (int ii = 0; ii < iterations; ii++) {
    if (add == 1) {
      pi = pi + (4.0/(3.0+ii*2));
      add = 0;
    } else {
      pi = pi - (4.0/(3.0+ii*2));
      add = 1;
    }
  }
  return pi;
}

int main(int argc, char *argv[]) {

  if ( argc != 2 ) {
    printf("Usage: %s <niter>",argv[0]);
    return 1;
  }
  const int iterations = atoi(argv[1]);

#pragma omp parallel
  {
    double pi = calculate_pi(iterations);
    printf("Thread %d, pi = %g\n",omp_get_thread_num(),pi);
  }
  return 0;
}

通过这种方式,您可以从命令行设置迭代次数,以及从环境变量设置线程数OMP_NUM_THREADS。例如:

export OMP_NUM_THREADS=4
./pi.x 1000

将以 1000 次迭代和 4 个线程运行可执行文件。

于 2012-10-22T08:22:39.917 回答
1

没有什么可以保证操作系统将创建与使用 pthread_create 生成线程一样多的内核级线程/任务。有一些 pthreads 实现可以在用户空间中做所有事情,并且只使用一个内核级线程和 cpu。许多(大多数?)实现将执行 1:1 线程,其中一个线程是一个内核级线程,因为它是最简单的实现。有些人将实现 M:N 混合模型,其中用户空间库决定产生多少内核级线程。您使用的实现可能就是这种情况。“ps -eLF”只会显示内核级线程,它没有关于用户级线程的信息。

M:N 线程的优势在于,在某些情况下,不同用户级线程之间的上下文切换可以更快。缺点是实现起来要复杂得多,而且通常实现非常脆弱。

于 2012-10-22T09:02:52.810 回答
1

当您的主线程创建一个新线程时,取决于您拥有多少 CPU 和其他一些东西,库/操作系统可以决定立即切换到新线程并运行该新线程,直到它阻塞或终止;然后切换回主线程,该线程创建另一个新线程,该线程一直运行直到它阻塞或终止,依此类推。在这种情况下,您永远不会同时运行超过 2 个线程(主线程和一个新线程)。

当然,你拥有的 CPU 越多,主线程就越有可能继续运行足够长的时间来产生所有新线程。我猜这就是发生的事情——你的 PC 的 CPU 比 ARM 系统多得多。

防止这种情况的最佳方法是使新线程的优先级低于主线程。这样,当较高优先级的主线程创建较低优先级的线程时,库/内核应该足够聪明,不会停止运行较高优先级的线程。

可悲的是,Linux 上 pthreads 的实现习惯于忽略正常的 pthreads 线程优先级。上次我研究它时,唯一的选择是使用实时线程优先级,这需要 root 访问权限并造成安全/权限灾难。这可能是由于内核中底层调度程序的限制(例如,pthreads 库无法解决的问题)。

还有另一种选择。如果您的主线程在创建任何新线程之前获取了一个互斥锁,并在创建所有新线程后将其释放,并且如果其他线程在执行任何实际工作之前尝试获取(并释放)相同的互斥锁;那么你会强制它同时拥有所有 7 个线程。

于 2012-10-22T10:24:25.880 回答
0

也许 1000 秒(在睡眠中)不足以完成那么多迭代。所以程序可能在 6 个线程完成之前退出。

你试过加入而不是睡觉吗?

尝试为此替换 sleep() :

for ( i = 0 ; i < NUM_THREADS; i++) {
    s = pthread_join(threads[i], NULL);
}
于 2012-10-22T08:04:08.353 回答