【问题标题】:how to compute sum of n/m Gregory-Leibniz terms in C language如何计算 C 语言中 n/m Gregory-Leibniz 项的总和
【发布时间】:2023-02-05 14:30:49
【问题描述】:

从命令行参数中获取名为 m & n 的两个值并将它们转换为整数。现在之后创建 m 个线程,每个线程计算 Gregory-Leibniz 级数中 n/m 项的总和。

pi = 4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - ...)

现在,当线程完成其计算时,打印其部分总和并将其自动添加到共享全局变量中。

以及如何检查所有 m 个计算线程是否都完成了原子加法?

我分享我的源代码,我尝试过的


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

pthread_barrier_t barrier;
int count;
long int term;
// int* int_arr;
double total;

void *thread_function(void *vargp)
{
    int thread_rank = *(int *)vargp;
    // printf("waiting for barrier... \n");
    
    pthread_barrier_wait(&barrier);
    // printf("we passed the barrier... \n");
    
    double sum = 0.0;
    int n = count * term;
    int start = n - term;
    
    // printf("start %d & end %d \n\n", start, n);
    for(int i = start; i < n; i++) 
    {
        sum += pow(-1, i) / (2*i+1);
        // v +=  1 / i - 1 / (i + 2);
    }
    total += sum; 
    // int_arr[count] = sum;
    count++;
    
    printf("thr %d : %lf \n", thread_rank, sum);
    
    return NULL;
}

int main(int argc,char *argv[])
{
    if (argc <= 2) {
        printf("missing arguments. please pass two num. in arguments\n");
        exit(-1);
    }
    
    int m = atoi(argv[1]); // get value of first argument
    int n = atoi(argv[2]); // get value of second argument
    // int_arr = (int*) calloc(m, sizeof(int));
    
    count = 1;
    term = n / m;

    pthread_t thread_id[m];
    int i, ret;
    double pi;
    
    /* Initialize the barrier. */
    pthread_barrier_init(&barrier, NULL, m);

    for(i = 0; i < m; i++)
    {
        ret = pthread_create(&thread_id[i], NULL , &thread_function, (void *)&i);
        if (ret) {
            printf("unable to create thread! \n");
            exit(-1);
        } 
    }
    
    for(i = 0; i < m; i++)
    {
        if(pthread_join(thread_id[i], NULL) != 0) {
            perror("Failed to join thread");
        }
    }
    
    pi = 4 * total;
    printf("%lf ", pi);
    
    pthread_barrier_destroy(&barrier);


    return 0;
}

我需要的 :-创建 M 个线程,每个线程计算 Gregory-Leibniz 级数中 n/m 项的总和。

第一个线程计算项 1 到 n/m 的总和,第二个线程计算从 (n/m + 1)2n/m 等项的总和。

当所有线程完成计算时,打印其部分总和和 Pi 的值。

我尝试了很多,但我无法准确地实现我想要的。我得到错误的 PI 输出值

例如:m = 16 和 n = 1024

然后它有时返回 3.125969,有时返回 12.503874,15.629843,有时返回 6.251937 作为 Pi 值的输出

请帮我

【问题讨论】:

  • 题外话:你认为 atoi() 在非整数的情况下会返回什么?你为什么要从void *投射到int *?这是不必要的,那里有一个隐式转换。“打印其部分总和并将其自动添加到共享全局变量中。”----> 所以你需要一个全局变量,但我没有看到。
  • void *thread_function(void *vargp) 暗示你应该返回一个指针,但你没有,所以程序会有未定义的行为。使用return NULL;(或pthread_exit(NULL);)结束您的 phtread 函数。
  • “你能帮我解决上面的问题吗”- 什么你的具体问题?“如何检查所有 m 个计算线程都完成了原子加法?”?你没有做任何添加。
  • 同样,这太广泛了。我们在这里回答有关特定问题的问题。您还没有展示您是如何尝试实现这一点的,因此我们看不到您遇到的问题。您已经证明您知道如何启动和加入线程,仅此而已。
  • 好的,首先要找到一个教程,然后尝试按照该教程进行操作。 pthread 如果您对此不确定,那么示例很多。我敢肯定,在某个地方也有关于如何计算 Gregory-Leibniz 级数中 n/m 项之和的示例。然后,如果您遇到任何问题,您将有一个具体问题要问。

标签: c multithreading pthreads pi


【解决方案1】:

在每个线程中,count 变量在此表达式中的值应稳定增加

int n = count * term;

比“上一个”线程中的大一个,但 count 仅在每个线程中增加。

即使您要“立即”增加计数,也没有什么可以防止两个或多个线程同时尝试读取和写入变量。

total 也存在同样的问题。

这些读写的不可预测性会导致不确定的结果。

在线程之间共享资源时,必须注意避免这些race conditionsPOSIX threads 库不包含任何原子操作。

您应该通过使用 lock 限制一次对单个线程的访问来保护您的关键数据免受读/写竞争条件的影响。

为此,POSIX 线程库包含一个 pthread_mutex_t 类型。看:


此外,正如 @Craig Estey 所指出的,使用 (void *) &amp;i 作为线程函数的参数会引入竞争条件,其中 i 的值可能会在任何给定线程执行 *(int *) vargp; 之前更改。

建议直接传递 i 的值,将其作为指针中间存储,但您应该使用适当的类型 intptr_tuintptr_t,它们已为此目的明确定义。

pthread_create(&thread_id[i], NULL , thread_function, (intptr_t) i)
int thread_rank = (intptr_t) vargp;

如何检查所有m 计算线程是否都完成了原子加法?

总结每个线程处理的术语数,并确保它等于预期的术语数。如果考虑到所有可能的错误(确保所有线程运行完成并假设使用的算法是正确的),那么自然也可以假设是这种情况。


一个比较完整的示例程序:

#define _POSIX_C_SOURCE 200809L
#include <inttypes.h>
#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct args {
    uint64_t thread_id;
    struct {
        uint64_t start;
        uint64_t end;
    } range;
};

pthread_mutex_t mutex;
long double total = 0;
uint64_t total_iterations = 0;

void *partial_sum(void *arg)
{
    struct args *args = arg;
    long double sum = 0;

    for (uint64_t n = args->range.start; n < args->range.end; n++)
        sum += pow(-1.0, n) / (1 + n * 2);

    if (pthread_mutex_lock(&mutex)) {
        perror("pthread_mutex_lock");
        exit(EXIT_FAILURE);
    }

    total += sum;
    total_iterations += args->range.end - args->range.start;

    if (pthread_mutex_unlock(&mutex)) {
        perror("pthread_mutex_unlock");
        exit(EXIT_FAILURE);
    }

    printf("thread(%" PRId64 ") Partial sum: %.20Lf
", args->thread_id, sum);

    return NULL;
}

int main(int argc,char **argv)
{
    if (argc < 3) {
        fprintf(stderr, "usage: %s THREADS TERMS
", *argv);
        return EXIT_FAILURE;
    }

    uint64_t threads = strtoull(argv[1], NULL, 10);
    uint64_t terms = strtoull(argv[2], NULL, 10);

    if (!threads || !terms) {
        fprintf(stderr, "Argument is zero.
");
        return EXIT_FAILURE;
    }

    uint64_t range = terms / threads;
    uint64_t excess = terms - range * threads;

    pthread_t thread_id[threads];
    struct args arguments[threads];

    if (pthread_mutex_init(&mutex, NULL)) {
        perror("pthread_mutex_init");
        return EXIT_FAILURE;
    }

    for (uint64_t i = 0; i < threads; i++) {
        arguments[i].thread_id = i;
        arguments[i].range.start = i * range;
        arguments[i].range.end = arguments[i].range.start + range;

        if (threads - 1 == i)
            arguments[i].range.end += excess;

        int ret = pthread_create(thread_id + i, NULL , partial_sum, arguments + i);

        if (ret) {
            perror("pthread_create");
            return EXIT_FAILURE;
        }
    }

    for (uint64_t i = 0; i < threads; i++)
        if (pthread_join(thread_id[i], NULL))
            perror("pthread_join");

    pthread_mutex_destroy(&mutex);

    printf("%.10Lf
", 4 * total);
    printf("COMPLETE? (%s)
", total_iterations == terms ? "YES" : "NO");
}

使用 16 个线程处理 10 亿个术语:

$ ./a.out 16 10000000000
thread(14) Partial sum: 0.00000000000190476190
thread(10) Partial sum: 0.00000000000363636364
thread(2) Partial sum: 0.00000000006666666667
thread(1) Partial sum: 0.00000000020000000000
thread(8) Partial sum: 0.00000000000555555556
thread(15) Partial sum: 0.00000000000166666667
thread(0) Partial sum: 0.78539816299744868408
thread(3) Partial sum: 0.00000000003333333333
thread(13) Partial sum: 0.00000000000219780220
thread(11) Partial sum: 0.00000000000303030303
thread(4) Partial sum: 0.00000000002000000000
thread(5) Partial sum: 0.00000000001333333333
thread(7) Partial sum: 0.00000000000714285714
thread(6) Partial sum: 0.00000000000952380952
thread(12) Partial sum: 0.00000000000256410256
thread(9) Partial sum: 0.00000000000444444444
3.1415926535
COMPLETE? (YES)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 2019-08-07
    相关资源
    最近更新 更多