Unix c 程序使用线程计算圆周率

Unix c program to calculate pi using threads

class 一直在做这个作业。将这段代码放在一起,但它给了我几个我无法解决的错误。

代码

#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 - 到 - 指针 - 转换] 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

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

阅读T 并知道大小后,您需要动态分配数组。在 C 中,您使用 malloc for that, in C++ you should use std::vector 代替。

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

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

int N, T;
double *vsum;

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

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/ 您将整数指针传递给线程函数,但这样做有两个问题。

首先是你把它提取成一个double 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);

虽然我不确定这样会更好。

或者(虽然有点麻烦),坚持你的指针解决方案,并确保没有竞争条件的可能性(通过为每个线程传递一个 unique 指针) .

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

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