Unix c程序使用线程计算pi

时间:2015-06-09 05:33:28

标签: c unix pthreads

正在为班级工作。将这些代码放在一起,但它给了我一些我无法解决的错误。

代码

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

//global variables
int N, T;
double vsum[T];

//pie function
void* pie_runner(void* arg)
{
    double *limit_ptr = (double*) arg;
    double j = *limit_ptr;

    for(int i = (N/T)*j; i<=((N/T)*(j+1)-1); j++)
    {
        if(i %2 =0)
            vsum[j] += 4/((2*j)*(2*j+1)*(2*j+2)); 
        else
            vsum[j] -= 4/((2*j)*(2*j+1)*(2*j+2));

    }

    pthread_exit(0);
}

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

    if(argc != 3) {
        printf("Error: Must send it 2 parameters, you sent %s", argc);
        exit(1);
    }
    N = atoi[1];
    T = atoi[2]; 

    if(N !> T) {
        printf("Error: Number of terms must be greater then number of threads.");
        exit(1);    
    }

    for(int p=0; p<T; p++)        //initialize array to 0
    {
        vsum[p] = 0;
    }

    double pie = 3;
    //launch threads
    pthread_t tids[T];

    for(int i = 0; i<T; i++)
    {
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_create(&tids[i], &attr, pie_runner, &i);
    }

    //wait for threads...
    for(int k = 0; k<T; k++)
    {
        pthread_join(tids[k], NULL);
    }

    for(int x=0; x<T; x++)
    {
        pie += vsum[x];
    }

    printf("pi computed with %d terms in %s threads is %k\n", N, T, pie);


}

我遇到的一个问题是阵列顶部。它需要是一个全局变量,但它一直告诉我它不是一个常量,即使我这样声明它。

任何帮助都表示赞赏,其余的代码也是如此。

**编辑:使用下面的注释更新代码后,这是新代码。我还有一些错误,并希望得到帮助处理它们。 1)警告:从指针转换为不同大小的整数[-Wpointer-to-int-cast] int j =(int)arg; 2)警告:从不同大小的整数转换为指针[Wint - to - pointer - cast] pthread_create(..........,(void *)i);

新代码:

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

//global variables
int N, T;
double *vsum;

//pie function
void* pie_runner(void* arg)
{
    long j = (long)arg;    
    //double *limit_ptr = (double*) arg;
    //double j = *limit_ptr;

    //for(int i = (j-1)*N/T; i < N*(j) /T; i++)
    for(int i = (N/T)*(j-1); i < ((N/T)*(j)); i++)
    {

        if(i % 2 == 0){
            vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2)); 
            //printf("vsum %lu = %f\n", j, vsum[j]);
                  }
        else{
            vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2));
            //printf("vsum %lu = %f\n", j, vsum[j]);
                  }


    }

    pthread_exit(0);
}

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

    if(argc != 3) {
        printf("Error: Must send it 2 parameters, you sent %d\n", argc-1);
        exit(1);
    }
    N = atoi(argv[1]);
    T = atoi(argv[2]); 

    vsum = malloc((T+1) * sizeof(*vsum));
    if(vsum == NULL) {
        fprintf(stderr, "Memory allocation problem\n");
        exit(1);
    }

    if(N <= T) {
        printf("Error: Number of terms must be greater then number of threads.\n");
        exit(1);    
    }

    for(int p=1; p<=T; p++)        //initialize array to 0
    {
        vsum[p] = 0;
    }

    double pie = 3.0;
    //launch threads
    pthread_t tids[T+1];

    for(long i = 1; i<=T; i++)
    {
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_create(&tids[i], &attr, pie_runner, (void*)i);
    }

    //wait for threads...
    for(int k = 1; k<=T; k++)
    {
        pthread_join(tids[k], NULL);
    }

    for(int x=1; x<=T; x++)
    {
        pie += vsum[x];
    }

    printf("pi computed with %d terms in %d threads is %.20f\n", N, T, pie);

    //printf("pi computed with %d terms in %d threads is %20f\n", N, T, pie);

    free(vsum);
}

值不起作用:

./pie1 2 1
pi computed with 2 terms in 1 threads is 3.00000000000000000000
./pie1 3 1
pi computed with 3 terms in 1 threads is 3.16666666666666651864
 ./pie1 3 2
pi computed with 3 terms in 2 threads is 3.13333333333333330373
 ./pie1 4 2
pi computed with 4 terms in 2 threads is 3.00000000000000000000
 ./pie1 4 1
pi computed with 4 terms in 1 threads is 3.00000000000000000000
 ./pie1 4 3
pi computed with 4 terms in 3 threads is 3.14523809523809516620
 ./pie1 10 1
pi computed with 10 terms in 1 threads is 3.00000000000000000000
 ./pie1 10 2
pi computed with 10 terms in 2 threads is 3.13333333333333330373
 ./pie1 10 3
pi computed with 10 terms in 3 threads is 3.14523809523809516620
 ./pie1 10 4
pi computed with 10 terms in 4 threads is 3.00000000000000000000
./pie1 10 5
pi computed with 10 terms in 5 threads is 3.00000000000000000000
./pie1 10 6
pi computed with 10 terms in 6 threads is 3.14088134088134074418
 ./pie1 10 7
pi computed with 10 terms in 7 threads is 3.14207181707181693042
./pie1 10 8
pi computed with 10 terms in 8 threads is 3.14125482360776464574
 ./pie1 10 9
pi computed with 10 terms in 9 threads is 3.14183961892940200045
./pie1 11 2
pi computed with 11 terms in 2 threads is 3.13333333333333330373
 ./pie1 11 4
pi computed with 11 terms in 4 threads is 3.00000000000000000000

2 个答案:

答案 0 :(得分:2)

该数组存在两个问题:第一个问题是T不是编译时常量,如果您使用C ++进行编程则需要它。第二个是T初始化为零,这意味着数组的大小为零,并且数组的所有索引都将超出范围。

一旦阅读T并知道大小,就需要动态分配数组。在C语言中,您可以使用malloc,在C ++中,您应该使用std::vector代替。

答案 1 :(得分:2)

该代码存在许多问题。您的具体问题是,在C中,不允许在文件范围内使用可变长度数组(VLA)。

因此,如果您希望该数组是动态的,则必须声明指向它的指针并自行分配:

int N, T;
double *vsum;

然后,在设置main()之后的T中:

vsum = malloc (T * sizeof(*vsum));
if (vsum == NULL) {
    fprintf (stderr, "Memory allocation problem\n");
    exit (1);
}

记得在退出之前释放它(不是技术要求但是形式好):

free (vsum);

其他问题包括:

1 / C中没有!>运算符,我怀疑该行应该是:

if (N > T) {

而不是:

if (N !> T) {

2 /要从命令行获取参数,请更改:

N = atoi[1];
T = atoi[2];

成:

N = atoi(argv[1]);
T = atoi(argv[2]);

3 /比较运算符为==,而非=,因此您需要更改:

if(i %2 =0)

成:

if (i % 2 == 0)

4 /关于没有足够参数的错误消息需要使用%d而不是%s,因为argc是一个完整的类型:

printf ("Error: Must send it 2 parameters, you sent %d\n", argc-1);

在最后同意您的计算消息(并修复浮点值的%k):

printf ("pi computed with %d terms in %d threads is %.20f\n", N, T, pie);

5 /你将一个整数指针传递给你的线程函数,但是有两个问题。

首先,您将其提取为双j,不能用作数组索引。如果它是一个传入的整数,它应该被转回一个整数。

第二个是,在主线程更改该值以启动另一个线程之前,无法保证新线程将提取值(或者甚至开始运行其代码)。你应该直接将整数转换为void *,而不是用整数指针搞乱。

要解决这两个问题,请在创建线程时使用它:

pthread_create (&tids[i], &attr, pie_runner, (void*)i);

这是在线程函数的开头:

int j = (int) arg;

如果您收到警告或遇到问题,可能是 ,因为您的整数和指针尺寸不兼容。在这种情况下,你可以尝试类似:

pthread_create (&tids[i], &attr, pie_runner, (void*)(intptr_t)i);

虽然我不确定会有更好的效果。

或者(虽然它有点像kludge),坚持你的指针解决方案,并确保没有竞争条件的可能性(通过传递唯一的指针线程)。

首先,将线程函数恢复为通过指针接收其值:

int j = *((int*) arg);

然后,在开始创建线程之前,您需要创建一个线程整数数组,并为每个创建的线程填充并传递该数组的正确索引(的地址):

int tvals[T];                   // add this line.
for (int i = 0; i < T; i++) {
    tvals[i] = i;               // and this one.
    pthread_attr_t attr;
    pthread_attr_init (&attr);
    pthread_create (&tids[i], &attr, pie_runner, &(tvals[i]));
}

除非你有这么多线程,否则不应该太繁重,因为estra数组会有问题。但是,如果您 许多线程,那么您将面临更大的问题。

6 /线程中的循环错误地递增j而不是i。由于这是下一节涉及的相同区域,我将在那里更正。

7 /在主要使用浮点计算时使用整数意味着您必须安排计算,以便它们不会截断分区,例如10 / 4 -> 2 where it should be 2.5

这意味着线程函数中的循环应该如下改变(包括像前一点一样递增i):

for (int i = j*N/T; i <= N * (j+1) / T - 1; i++)
    if(i % 2 == 0)
        vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2));
    else
        vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2));

使用所有这些更改,您会得到一个合理合理的结果:

$ ./picalc 100 101
pi computed with 100 terms in 101 threads is 3.14159241097198238535