当前位置: 首页 > news >正文

C多线程编程- 近似求解π

本程序使用蒙特卡洛方法估算圆周率(π)。它首先创建了指定数量的线程,每个线程生成一个随机点并检查该点是否在单位圆内。基于这些线程的结果,程序计算在单位圆内的点的比例,并乘以4来估算π的值。为了对比,程序还直接在主线程中(没有并发)进行了相同的π估算过程(由于每次都是生成随机数,所以这个基准也没啥意义hh~)。最后,程序打印出两种方法得到的π值。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>struct arg_t {float x;float y;
};void *start(void *arg) {struct arg_t *ll = (struct arg_t *)arg;float x1 = ll->x;float y1 = ll->y;long M = 0;if (x1*x1 + y1*y1 <= 1.0) {M ++;}pthread_exit((void *)M);
}int main(int argc, char **argv) {if (argc < 2) {fprintf(stderr, "Please provide a number as an argument.\n");exit(1);}long N1 = atol(argv[1]);// printf("%ld\n", N1);pthread_t tids[N1];// pai(concurrency)for (long i = 0; i < N1; ++ i) {struct arg_t *arg = malloc(sizeof(struct arg_t));int x = rand();int y = rand();arg->x = 1.0*x / RAND_MAX;arg->y = 1.0*y / RAND_MAX;pthread_create(&tids[i], 0, start, arg);}void *res = 0;long M = 0;for (long i = 0; i < N1; ++ i) {pthread_join(tids[i], &res);M += (long)res;}printf("pai = %f\n", 4.0*M/N1);  // concurrency// pai(oracle)M = 0;for (long i = 0; i < N1; ++ i) {int x = rand();int y = rand();float x1 = 1.0*x / RAND_MAX;float y1 = 1.0*y / RAND_MAX;if (x1*x1 + y1*y1 <= 1.0) {M ++;}}printf("pai = %f\n", 4.0*M/N1);  // oraclepthread_exit(0);
}

测试一下上述程序:

majn@tiger:~$ ./pai 10000
pai = 3.171200
pai = 3.142000
majn@tiger:~$ ./pai 100000
Segmentation fault (core dumped)

分析Segmentation fault的原因:

在上面的程序中,为每个线程都动态分配了 arg_t 结构的内存,但在线程执行完毕后,这些内存并没有被释放。虽然这不是立即的问题,但长期这样会导致内存泄露。应该在线程函数中或 pthread_join 之后释放这些内存。

改进方案:

一种方法是在线程函数 start 的结尾释放它(插个眼hh~)。但由于在主函数中可能还需要访问这些结构,更安全的方法是在 pthread_join 之后释放这些动态分配的内存。

修改上述代码:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>struct arg_t {float x;float y;
};void *start(void *arg) {struct arg_t *ll = (struct arg_t *)arg;float x1 = ll->x;float y1 = ll->y;long M = 0;if (x1*x1 + y1*y1 <= 1.0) {M ++;}pthread_exit((void *)M);
}int main(int argc, char **argv) {if (argc < 2) {fprintf(stderr, "Please provide a number as an argument.\n");exit(1);}long N1 = atol(argv[1]);struct arg_t *args[N1];// printf("%ld\n", N1);pthread_t tids[N1];// pai(concurrency)for (long i = 0; i < N1; ++ i) {args[i] = malloc(sizeof(*args[i]));// struct arg_t *arg = malloc(sizeof(*arg));int x = rand();int y = rand();args[i]->x = 1.0*x / RAND_MAX;args[i]->y = 1.0*y / RAND_MAX;pthread_create(&tids[i], 0, start, args[i]);}void *res = 0;long M = 0;for (long i = 0; i < N1; ++ i) {pthread_join(tids[i], &res);M += (long)res;free(args[i]);}printf("pai = %f\n", 4.0*M/N1);  // concurrency// pai(oracle)M = 0;for (long i = 0; i < N1; ++ i) {int x = rand();int y = rand();float x1 = 1.0*x / RAND_MAX;float y1 = 1.0*y / RAND_MAX;if (x1*x1 + y1*y1 <= 1.0) {M ++;}}printf("pai = %f\n", 4.0*M/N1);  // oraclepthread_exit(0);
}

这样,每次线程执行完毕并被主线程收回后,对应的动态分配的内存都会被释放。

测试一下修改后的程序:

majn@tiger:~$ ./pai 100000
pai = 3.721760
pai = 3.137640
majn@tiger:~$ ./pai 1000000
Segmentation fault (core dumped)

好好好,这样玩儿是吧。

分析Segmentation fault的原因:

仔细观察上面的程序,我使用了一个固定大小的线程数组:pthread_t tids[N1];。对于大的 N1 值,这可能会导致栈溢出。在大多数系统上,默认的栈大小可能不足以容纳大量的 pthread_t 变量。

改进方案:

考虑动态分配线程ID数组的空间。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>struct arg_t {float x;float y;
};void *start(void *arg) {struct arg_t *ll = (struct arg_t *)arg;float x1 = ll->x;float y1 = ll->y;long M = 0;if (x1*x1 + y1*y1 <= 1.0) {M ++;}pthread_exit((void *)M);
}int main(int argc, char **argv) {if (argc < 2) {fprintf(stderr, "Please provide a number as an argument.\n");exit(1);}long N1 = atol(argv[1]);struct arg_t *args[N1];// printf("%ld\n", N1);pthread_t *tids = malloc(N1 * sizeof(pthread_t));// pai(concurrency)for (long i = 0; i < N1; ++ i) {args[i] = malloc(sizeof(*args[i]));// struct arg_t *arg = malloc(sizeof(*arg));int x = rand();int y = rand();args[i]->x = 1.0*x / RAND_MAX;args[i]->y = 1.0*y / RAND_MAX;pthread_create(&tids[i], 0, start, args[i]);}void *res = 0;long M = 0;for (long i = 0; i < N1; ++ i) {pthread_join(tids[i], &res);M += (long)res;free(args[i]);}printf("pai = %f\n", 4.0*M/N1);  // concurrency// pai(oracle)M = 0;for (long i = 0; i < N1; ++ i) {int x = rand();int y = rand();float x1 = 1.0*x / RAND_MAX;float y1 = 1.0*y / RAND_MAX;if (x1*x1 + y1*y1 <= 1.0) {M ++;}}printf("pai = %f\n", 4.0*M/N1);  // oraclepthread_exit(0);
}
majn@tiger:~$ ./pai 1000000
pai = 3.972176
pai = 3.142136
majn@tiger:~$ ./pai 10000000
Segmentation fault (core dumped)

???不玩儿了!!! 到此为止,我们把输入数据的规模N1从一开始最大接受10000扩大到现在最大接受1000000。

彩蛋: 要不然把为每个线程都动态分配的 arg_t 结构在线程函数 start 的结尾释放试一试?

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>struct arg_t {float x;float y;
};void *start(void *arg) {struct arg_t *ll = (struct arg_t *)arg;float x1 = ll->x;float y1 = ll->y;long M = 0;if (x1*x1 + y1*y1 <= 1.0) {M ++;}free(arg);pthread_exit((void *)M);
}int main(int argc, char **argv) {if (argc < 2) {fprintf(stderr, "Please provide a number as an argument.\n");exit(1);}long N1 = atol(argv[1]);// printf("%ld\n", N1);// pthread_t tids[N1];pthread_t *tids = malloc(N1 * sizeof(pthread_t));// pi(concurrency)for (long i = 0; i < N1; ++ i) {struct arg_t *arg = malloc(sizeof(struct arg_t));int x = rand();int y = rand();arg->x = 1.0*x / RAND_MAX;arg->y = 1.0*y / RAND_MAX;pthread_create(&tids[i], 0, start, arg);}void *res;long M = 0;for (long i = 0; i < N1; ++ i) {pthread_join(tids[i], &res);M += (long)res;}printf("pai = %f\n", 4.0*M/N1);  // concurrency// pi(oracle)M = 0;for (long i = 0; i < N1; ++ i) {int x = rand();int y = rand();float x1 = 1.0*x / RAND_MAX;float y1 = 1.0*y / RAND_MAX;if (x1*x1 + y1*y1 <= 1.0) {M ++;}}printf("pai = %f\n", 4.0*M/N1);  // oraclepthread_exit(0);
}
majn@tiger:~$ ./pai_init 10000000
pai = 3.997218
pai = 3.141381
majn@tiger:~$ ./pai_init 100000000
pai = 3.999722
pai = 3.141420
majn@tiger:~$ ./pai_init 1000000000
^C   // 时间太长了,不想等了

Amazing!!!怎么这么神奇?


注: 蒙特卡洛方法(Monte Carlo method)是一种通过随机抽样来获得数值解的统计方法。这个方法得名于摩纳哥的蒙特卡洛赌场,因为它大量使用随机性和概率。蒙特卡洛方法在物理学、工程学、经济学和许多其他领域都有广泛的应用。

关键概念和特点:

  1. 随机抽样:这是蒙特卡洛方法的核心。为了得到一个问题的数值解,这个方法使用随机数或更通常地说,使用伪随机数。

  2. 统计结果:通过对大量的随机样本进行统计分析,得到的是一个近似解,而不是确切的解。

  3. 精度与样本数量:通常,随着样本数量的增加,估算的精度也会提高。但是,为了使误差减少到原来的一半,样本数通常需要增加四倍。

  4. 应用:蒙特卡洛方法在多种应用中都非常有用,尤其是在问题的解析解很难得到或者不存在时。例如,它被用于估算复杂积分、求解难以解析的统计物理问题、进行金融市场模拟等。

  5. 示例 - 估算π:一个经典的应用是使用蒙特卡洛方法估算π的值。方法是这样的:随机投掷点到单位正方形内,统计落在单位圆内的点的数量。落在圆内的点数与总点数的比例,乘以4,就给出了π的近似值。

简而言之,蒙特卡洛方法是一种利用随机性来求解问题的技术,通过对大量样本的统计分析来获得结果。

相关文章:

C多线程编程- 近似求解π

本程序使用蒙特卡洛方法估算圆周率&#xff08;π&#xff09;。它首先创建了指定数量的线程&#xff0c;每个线程生成一个随机点并检查该点是否在单位圆内。基于这些线程的结果&#xff0c;程序计算在单位圆内的点的比例&#xff0c;并乘以4来估算π的值。为了对比&#xff0c…...

YOLOV7量化第二步: 模型标定

2.模型标定 当然可以&#xff0c;模型量化中的标定&#xff08;calibration&#xff09;是一个关键过程&#xff0c;它主要确保在降低计算精度以减少模型大小和提高推理速度的同时&#xff0c;不会显著损害模型的准确性。现在&#xff0c;我将根据您提供的步骤解释这一过程。 …...

前端-uniapp-开发指南

美团外卖微信小程序开发 uniapp-美团外卖微信小程序开发P1 成果展示P2外卖小程序后端&#xff0c;学习给小程序写http接口P3 主界面配置P4 首页组件拆分P13 外卖列表布局筛选组件商家 布局测试数据创建样式 请求商家外卖数据封装请求并发请求 uni-app框架调用https接口 开发小程…...

Java集合类ArrayList的应用-杨辉三角的前n行

目录 一、题目 杨辉三角 二、题解 三、代码 四、总结 一、题目 题目链接&#xff1a;https://leetcode.cn/problems/pascals-triangle/description/ 杨辉三角 题目描述&#xff1a;给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨…...

C语言-函数

函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数&#xff0c;即主函数 main() 。 主函数可以调用其他函数&#xff0c;其他函数也可以相互调用&#xff0c;用户也可以那个自定义函数。 函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实…...

蓝桥杯 枚举算法 (c++)

枚举就是根据提出的问题&#xff0c;——列出该问题的所有可能的解&#xff0c;并在逐一列出的过程中&#xff0c;检验每个可能解是否是问题的真正解&#xff0c; 如果是就采纳这个解&#xff0c;如果不是就继续判断下一个。 枚举法一般比较直观&#xff0c;容易理解&#xff0…...

Wordpress自定义小工具logo调用设置(可视化)

在主题开发中&#xff0c;需要调用网站的logo&#xff0c;最简单的办法就是用wp自带的函数&#xff0c;那就是the_custom_logo()&#xff0c;使用它还可以通过后台-自定义-logo&#xff0c;边修改边预览&#xff0c;还是很香的。 自定义徽标支持应首先使用add_theme_support()添…...

面试常考数据结构:红黑树、B树、B+树各自适用的场景

1. 磁盘基础知识 分页&#xff1a; 现代操作系统都使用虚拟内存来印射到物理内存&#xff0c;内存大小有限且价格昂贵&#xff0c;所以数据的持久化是在磁盘上。虚拟内存、物理内存、磁盘都使用页作为内存读取的最小单位。一般一页为4KB&#xff08;8个扇区&#xff0c;每个扇…...

Paddle GPU版本需要安装CUDA、CUDNN

完整的教程 深度学习环境配置&#xff1a;linuxwindows系统下的显卡驱动、Anaconda、Pytorch&Paddle、cuda&cudnn的安装与说明 - 知乎这篇文档的内容是尽量将深度学习环境配置(使用GPU)所需要的内容做一些说明&#xff0c;由于笔者只在windows和linux下操作过&#xf…...

MYSQL length函数

mysql length函数计算结果的单位是啥&#xff0c;和varchar字段类型的单位是相同的吗&#xff1f; 做了一下实验&#xff0c;结果如下&#xff1a; 1.mysql length 函数计算的是有多少个字符&#xff0c;比如字段值是 permission 则length函数计算结果为10。 2.如果字段类型是…...

uniapp 在android手机上运行tab栏页面跳转问题

【问题描述】&#xff1a; 使用uniapp写的项目&#xff0c;在tab页面&#xff0c;无论使用哪种方式的跳转&#xff0c;只要是在url后面拼接参数&#xff0c;在打包成apk文件后&#xff0c;在手机上面安装使用&#xff0c;都是获取不到susIndex参数的&#xff0c;而在浏览器上面…...

css3 hover效果

CSS3中的:hover伪类用于创建鼠标悬停时的样式效果。当用户将鼠标悬停在页面元素上时&#xff0c;你可以为这些元素定义不同的样式规则&#xff0c;以实现交互效果 /* 一般样式规则 */ element {/* 正常状态下的样式 */ }/* 悬停样式规则 */ element:hover {/* 鼠标悬停时的样式…...

C语言char与short取反以及符号判断问题

这个问题主要是在从对一个变量进行符号判断引出&#xff0c;有一种判断方法是#define ISUNSIGNED(Value) (Value >0 && ~Value >0) 主要是通过将符号位取反然后将变量与0进行比较。传入int与unsigned int结果正确&#xff0c;但是当传入unsigned char 与unsign…...

Gpt-4多模态功能强势上线,景联文科技多模态数据采集标注服务等您来体验!

就在上个月&#xff0c;OpenAI 宣布对ChatGPT 进行重大更新&#xff0c;该模型不仅能够通过文字输入进行识别和分析&#xff0c;还能够通过语音、图像甚至视频等多种模态的输入来获取、识别、分析和输出信息。这一重要技术突破&#xff0c;将促进多模态自然语言处理的发展&…...

【idea】 java: 找不到符号

idea 启动时提示 java: 找不到符号 java: 找不到符号 符号: 方法 getCompanyDisputeCount() 位置: 类型为com.yang.entity.AreaAnalyse的变量 areaAnalyse 在setting ——> Compiler ——>Shared build process VM options: 添加&#xff1a; -Djps.track.ap.dep…...

Flink测试利器之DataGen初探 | 京东云技术团队

什么是 Flinksql Flink SQL 是基于 Apache Calcite 的 SQL 解析器和优化器构建的&#xff0c;支持ANSI SQL 标准&#xff0c;允许使用标准的 SQL 语句来处理流式和批处理数据。通过 Flink SQL&#xff0c;可以以声明式的方式描述数据处理逻辑&#xff0c;而无需编写显式的代码…...

linux更换常用软件的默认缓存路径(.conda, .huggingface等)

在使用linux的过程中&#xff0c;我们往往会使用软件安装很多packages&#xff0c;其中的大多数软件&#xff08;例如conda&#xff09;会把当前安装的packages缓存起来&#xff0c;以加速之后的相同package的安装。 而很多软件的默认缓存路径是user自己的home路径。下面罗列几…...

Kafka消费者使用案例

本文代码链接&#xff1a;https://download.csdn.net/download/shangjg03/88422633 1.消费者和消费者群组 在 Kafka 中&#xff0c;消费者通常是消费者群组的一部分&#xff0c;多个消费者群组共同读取同一个主题时&#xff0c;彼此之间互不影响。Kafka 之所以要引入消费者群组…...

SpringMVC全注解开发

在学习过程中&#xff0c;框架给我们最大的作用&#xff0c;就是想让开发人员尽可能地只将精力放在具体业务功能的实现之上&#xff0c;而对于各种映射关系的配置&#xff0c;统统由框架来进行完成&#xff0c;由此&#xff0c;注解就很好的将映射功能进行实现&#xff0c;并且…...

解决 android Cannot access ‘<init>‘: it is private in

最近要在2个非直接依赖module使用单例&#xff0c;有一种注入依赖的方式可以&#xff0c;但是报了如下错误&#xff1a; Cannot access <init>: it is private in 经过查阅资料&#xff0c;原来是依赖的单例类的构造函数不能使用private&#xff0c;这里做个记录&#…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...