C语言实现多线程计算n个数的和

C语言实现多线程计算n个数的和

需要使用 api

thread_create

#include <threads.h>
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
// thrd_t 是进程标识
// thrd_start_t 是函数指针,定义为int (*)(void *)

使用方式

  • 定义一个 thrd_t th;
  • 然后使用时传入 thrd_create(&th, func, (void *)arg)
  • 执行成功返回 thrd_success

thread_join

int thrd_join(thrd_t thr, int *result); 

等待传入的线程执行结束,result接收传入线程执行函数的返回值

thread_detach

int thrd_detach(thrd_t thrd);

逻辑上不需要等待线程结束,则使用该函数,释放传入的thrd所占资源。

/* ************************************************************************
> File Name:     multithread_1.c
> Author:        FeoBay
> mail:          feobay@foxmail.com
> Created Time:  Wed 20 Dec 2023 09:28:09 AM CST
> Description:   
 ************************************************************************/

#include <stdio.h>

#include <threads.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>

#define MAX_THREADS 8
#define MIN_BLOCK_SIZE 100

typedef struct {
    float *start; // 8字节,传递给parallel_sum()的数组块的起始地址
    int len;    // 数组块长度
    int block_size; // 每个线程中计算的数组块长度(block_size, 当线程实际分得的len <= block_size时就开始求和)
    double sum; // 求和结果
} Sum_arg;


// int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
// thrd_t 是一个对象类型

int parallel_sum(void *arg); // 线程函数的原型

// 计算数组元素的和,并写入*sumPtr
// sum()调用函数parallel_sum() 进行并行处理
// 返回值:如果没有发生错误,则返回true;否则返回true
bool sum(float arr[], int len, double *sumPtr) {
    int block_size = len / MAX_THREADS + 5; // 为了防止由于下取整导致block_size偏小,而导致线程比实际偏多,所以+5
    if (block_size < MIN_BLOCK_SIZE) block_size = len;

    Sum_arg args = {arr, len, block_size, 0.0};
    if (parallel_sum(&args)) {
        *sumPtr = args.sum;
        return true;
    } else {
        return false;
    }
}

// 递归辅助函数,用以将工作分解到几个线程中运行
int parallel_sum(void *arg) {
    Sum_arg *argp = (Sum_arg *)arg; // 指向参数的指针

    if (argp->len <= argp->block_size) { // 如果数组总长度小于线程分得的块大小,那么直接计算数组所有的和
        for (int i = 0; i < argp->len; ++i) {
            argp->sum += argp->start[i];
        }
        return 1;
    } else { // 如果len大于block_size,分解数组
        int mid = argp->len / 2;
        Sum_arg arg2 = {argp->start + mid, argp->len - mid, argp->block_size, 0}; // 后一半数组长度
        argp->len = mid; // 前一半数组长度

        thrd_t th;
        int res = 0;
        if (thrd_create(&th, parallel_sum, arg) != thrd_success) {
            return 0; // 没能创建新线程,则返回0
        }
        
        // 会递归调用,继续往下分,
        if (!parallel_sum(&arg2)) { // 在该递归函数下面还会继续创建线程
            thrd_detach(th); // 递归调用失败,释放线程
            return 0;
        }

        thrd_join(th, &res); // 等待其分出的线程执行完毕,再往后执行

        if (!res) return 0; // 出错
        
        // 对于
        argp->sum += arg2.sum;
        return 1;
    }
}

int main() {    
    srand(time(0));
    const int N = 1000;
    float arr[N];
    float std_sum = 0;
    for (int i = 0; i < N; ++i) {
        arr[i] = i + 1;
        std_sum += i + 1;
    }
    double res = 0;
    if (!sum(arr, N, &res)) {
        printf("Fail!\n");
        return 0;
    }
    printf("res = %lf\n", res);
    printf("std_sum = %lf\n", std_sum);
    return 0;
}

parallel_sum函数递归图

6a0f34eef6770e702a7f13c002eeeeda

PS:关于线程所占有的进程资源,可以参考这篇文章:线程间到底共享了哪些进程资源?

线程的私有资源:每个线程都有自己私有的栈区,但是线程并没有做出隔离不同栈区的保护机制,也就是说线程A可以修改线程B的栈区。

线程运行的本质其实就是函数的执行,函数的执行总会有一个源头,这个源头就是所谓的入口函数,CPU从入口函数开始执行从而形成一个执行流,只不过我们人为的给执行流起一个名字,这个名字就叫线程。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值