0
让我首先说这是为了学校,但我真的不需要帮助,我只是因为我得到的一些结果而感到困惑。C-pthreads似乎只使用一个核心
我有一个简单的程序,使用辛普森的规则逼近pi,在一个任务中,我们必须通过产生4个子进程来完成此任务,现在在这个任务中我们必须使用4个内核级线程。我已经这样做了,但是当我计划使用子进程的时候,运行速度似乎更快(我得到的印象我应该会看到相反的结果)。
下面是使用并行线程的程序:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
// This complicated ternary statement does the bulk of our work.
// Basically depending on whether or not we're at an even number in our
// sequence we'll call the function with x/32000 multiplied by 2 or 4.
#define TERN_STMT(x) (((int)x%2==0)?2*func(x/32000):4*func(x/32000))
// Set to 0 for no 100,000 runs
#define SPEED_TEST 1
struct func_range {
double start;
double end;
};
// The function defined in the assignment
double func(double x)
{
return 4/(1 + x*x);
}
void *partial_sum(void *r)
{
double *ret = (double *)malloc(sizeof(double));
struct func_range *range = r;
#if SPEED_TEST
int k;
double begin = range->start;
for (k = 0; k < 25000; k++)
{
range->start = begin;
*ret = 0;
#endif
for (; range->start <= range->end; ++range->start)
*ret += TERN_STMT(range->start);
#if SPEED_TEST
}
#endif
return ret;
}
int main()
{
// An array for our threads.
pthread_t threads[4];
double total_sum = func(0);
void *temp;
struct func_range our_range;
int i;
for (i = 0; i < 4; i++)
{
our_range.start = (i == 0) ? 1 : (i == 1) ? 8000 : (i == 2) ? 16000 : 24000;
our_range.end = (i == 0) ? 7999 : (i == 1) ? 15999 : (i == 2) ? 23999 : 31999;
pthread_create(&threads[i], NULL, &partial_sum, &our_range);
pthread_join(threads[i], &temp);
total_sum += *(double *)temp;
free(temp);
}
total_sum += func(1);
// Final calculations
total_sum /= 3.0;
total_sum *= (1.0/32000.0);
// Print our result
printf("%f\n", total_sum);
return EXIT_SUCCESS;
}
下面是一个使用子进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
// This complicated ternary statement does the bulk of our work.
// Basically depending on whether or not we're at an even number in our
// sequence we'll call the function with x/32000 multiplied by 2 or 4.
#define TERN_STMT(x) (((int)x%2==0)?2*func(x/32000):4*func(x/32000))
// Set to 0 for no 100,000 runs
#define SPEED_TEST 1
// The function defined in the assignment
double func(double x)
{
return 4/(1 + x*x);
}
int main()
{
// An array for our subprocesses.
pid_t pids[4];
// The pipe to pass-through information
int mypipe[2];
// Counter for subproccess loops
double j;
// Counter for outer loop
int i;
// Number of PIDs
int n = 4;
// The final sum
double total_sum = 0;
// Temporary variable holding the result from a subproccess
double temp;
// The partial sum tallied by a subproccess.
double sum = 0;
int k;
if (pipe(mypipe))
{
perror("pipe");
return EXIT_FAILURE;
}
// Create the PIDs
for (i = 0; i < 4; i++)
{
// Abort if something went wrong
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
}
else if (pids[i] == 0)
// Depending on what PID number we are we'll only calculate
// 1/4 the total.
#if SPEED_TEST
for (k = 0; k < 25000; ++k)
{
sum = 0;
#endif
switch (i)
{
case 0:
sum += func(0);
for (j = 1; j <= 7999; ++j)
sum += TERN_STMT(j);
break;
case 1:
for (j = 8000; j <= 15999; ++j)
sum += TERN_STMT(j);
break;
case 2:
for (j = 16000; j <= 23999; ++j)
sum += TERN_STMT(j);
break;
case 3:
for (j = 24000; j < 32000; ++j)
sum += TERN_STMT(j);
sum += func(1);
break;
}
#if SPEED_TEST
}
#endif
// Write the data to the pipe
write(mypipe[1], &sum, sizeof(sum));
exit(0);
}
}
int status;
pid_t pid;
while (n > 0)
{
// Wait for the calculations to finish
pid = wait(&status);
// Read from the pipe
read(mypipe[0], &temp, sizeof(total_sum));
// Add to the total
total_sum += temp;
n--;
}
// Final calculations
total_sum /= 3.0;
total_sum *= (1.0/32000.0);
// Print our result
printf("%f\n", total_sum);
return EXIT_SUCCESS;
}
这里是并行线程版本time
结果运行10万次:
real 11.15
user 11.15
sys 0.00
这里是子进程版本:
real 5.99
user 23.81
sys 0.00
拥有23.81的用户时间意味着这是每个内核执行代码所花时间的总和。在pthread分析中,实际/用户时间相同,这意味着仅使用一个内核。为什么不使用全部4核?我认为默认情况下它可能比子进程更好。
希望这个问题是有道理的,这是我第一次用pthread编程,而且我对OS级编程一般都很陌生。
感谢您花时间阅读这个冗长的问题。
我将for循环外面的'pthread_join'移动到了它自己的for循环中,并添加了free和free,但是现在每次都有不同的答案......显然,我并不了解线程的一些内容,是有什么我能读懂的,展示了如何解决这类问题? – LainIwakura
@LainIwakura:你的意思是“请解释多线程编程如何在双行注释中起作用”?恐怕这有点超出范围。你的班级没有教这个吗? –
我讨厌说这个,但是这个班很烂。我想出了为什么我得到了不同的值 - 线程共享范围结构。我通过建立一系列结构来解决这个问题......现在我得到了正确的答案,但程序更慢了! (16.52实时,65.05用户时间!) 它看起来像我的核心正在使用,但性能没有超过程序的版本使用fork() – LainIwakura