首页 > 系统相关 >操作系统(7) (POSIX--Linux线程编程---使用多线程计算平方pthread_t/create/join应用)

操作系统(7) (POSIX--Linux线程编程---使用多线程计算平方pthread_t/create/join应用)

时间:2024-10-29 23:19:06浏览次数:8  
标签:-- void number int 线程 result pthread 多线程

1. 代码目的

我们希望创建一个程序:

  1. 启动多个线程,每个线程计算一个数字的平方值。
  2. 每个线程将计算结果返回给主线程。
  3. 主线程接收每个线程的返回值,并将结果打印出来。

在这个例子中,我们通过传递不同的参数给每个线程,来让每个线程计算不同数字的平方值。


2. 代码实现

以下是代码的完整实现:

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

#define NUMBER_OF_PROCESS 5  // 定义线程数量

// 线程函数,用于计算输入数字的平方
void* square(void* param) {
    int a = *(int*) param;  // 将参数转换为int指针并解引用
    int* result = (int*) malloc(sizeof(int));  // 动态分配内存存储返回值
    *result = a * a;  // 计算平方
    return result;  // 返回结果
}

int main(int argc, char const *argv[]) {
    int number = NUMBER_OF_PROCESS;
    pthread_t t1_id[number];  // 用于存储线程ID
    int* result;  // 用于存储线程返回值

    for (int i = 0; i < number; i++) {
        // 创建线程,传递i作为参数
        pthread_create(&t1_id[i], NULL, square, &i);
        pthread_join(t1_id[i], (void**) &result);  // 等待线程完成并获取返回值
        printf("The %d thread input number is %d, result is %d\n", i, i, *result);
        free(result);  // 释放动态分配的内存
    }

    return 0;
}

3. 代码逐行解析

全局定义
#define NUMBER_OF_PROCESS 5

宏定义NUMBER_OF_PROCESS指定了要创建的线程数量,在这里我们设置为5。这样方便在代码中灵活更改线程数量。

线程函数 square
void* square(void* param) {
    int a = *(int*) param;  // 将参数转换为int指针并解引用
    int* result = (int*) malloc(sizeof(int));  // 动态分配内存存储返回值
    *result = a * a;  // 计算平方
    return result;  // 返回结果
}
  • 参数处理param是一个void*指针,传递的是整数的地址。将其转换为int*指针后,使用*param来获取传入的整数值。
  • 内存分配:使用malloc在堆上分配一个int大小的内存,用于存储计算结果。这样当线程返回时,主线程可以通过指针访问该结果。
  • 返回值:返回指向结果的指针(result),可以在主线程中通过pthread_join获取。
主函数 main
int main(int argc, char const *argv[]) {
    int number = NUMBER_OF_PROCESS;
    pthread_t t1_id[number];
    int* result;
    
    for (int i = 0; i < number; i++) {
        pthread_create(&t1_id[i], NULL, square, &i);  // 创建线程并传递参数
        pthread_join(t1_id[i], (void**) &result);  // 等待线程完成并获取返回值
        printf("The %d thread input number is %d, result is %d\n", i, i, *result);
        free(result);  // 释放动态分配的内存
    }

    return 0;
}
  • 线程创建:在for循环中,通过pthread_create创建线程,并传入线程函数square。每次循环中,将i的地址传递给square函数。注意,这里传递的是变量i的地址。
  • 线程同步:使用pthread_join等待每个线程完成,并获取其返回的结果。pthread_join的第二个参数是一个void**指针,通过强制类型转换,我们可以将其转为int*类型并存储到result中。
  • 打印和释放内存:打印线程返回的平方结果后,使用free(result);释放动态分配的内存,防止内存泄漏。

4. 存在的问题:数据竞争

当前代码在传递参数&i时会产生数据竞争,因为所有线程共享变量i。当pthread_create启动线程时,如果在线程访问变量i之前主线程的i值已经更新,那么线程读取的值可能不正确,导致错误结果。

5. 解决方法:使用单独的参数数组

通过定义一个参数数组,将每个线程的参数存储在独立的位置,可以避免数据竞争问题。以下是改进后的代码:

int main(int argc, char const *argv[]) {
    int number = NUMBER_OF_PROCESS;
    pthread_t t1_id[number];
    int args[number];  // 参数数组,每个线程一个独立参数
    int* result;
    
    for (int i = 0; i < number; i++) {
        args[i] = i;  // 将每个线程的参数存储在独立的数组位置中
        pthread_create(&t1_id[i], NULL, square, &args[i]);
        pthread_join(t1_id[i], (void**) &result);
        printf("The %d thread input number is %d, result is %d\n", i, i, *result);
        free(result);
    }

    return 0;
}

6. 运行结果示例

假设线程的输入值分别是01234,输出结果应该如下:

The 0 thread input number is 0, result is 0
The 1 thread input number is 1, result is 1
The 2 thread input number is 2, result is 4
The 3 thread input number is 3, result is 9
The 4 thread input number is 4, result is 16

7. 关键知识点总结

  • 线程函数参数传递:使用void*来传递不同类型的参数,传递后在函数内部将其转换回正确的类型。
  • 动态内存分配:在线程函数中,使用malloc分配内存以返回计算结果。主线程在使用完返回值后,需要调用free释放内存。
  • 数据竞争与解决方案:避免数据竞争的一个常用方法是为每个线程创建独立的参数,而不是共享同一个变量。

总结

本文通过一个简单的线程计算平方值的例子,介绍了pthread库的基础用法。我们学习了如何传递参数、获取线程返回值,并讨论了内存管理和数据竞争的问题。希望这个示例可以帮助你理解多线程编程的基础概念和实现方法。

标签:--,void,number,int,线程,result,pthread,多线程
From: https://blog.csdn.net/2301_80176774/article/details/143352479

相关文章

  • 微信如何快速保存聊天里的原图
    8-8如果你的工作需要每天都从某些微信的群里不停地保存聊天收到的图片下来,那本文章的方法就非常适合你尝试,本文将教你如何自动地把微信的聊天中收到的图片,自动地保存下来,24小时不间断。大概的思路是在电脑上运行一个软件,这个软件可以实时地检测聊天时收到的文件,其中图片也是一种文......
  • 【云原生】云原生后端:安全性最佳实践
    目录引言一、身份管理1.1身份验证1.2身份授权二、数据加密2.1数据静态加密2.2数据传输加密2.3密钥管理三、网络安全3.1网络隔离3.2防火墙与入侵检测3.3安全组与网络访问控制列表(NACL)结论引言在云原生架构中,安全性是一个至关重要的考量。随着应用不断演......
  • 小米迎来「新起点」:硬核创新从超越到引领
    10月29日,小米15系列暨小米澎湃OS2新品发布会在北京召开,小米集团创始人、董事长兼CEO雷军宣布了小米汽车原型车在纽北跑出6分46秒874的圈速,登顶“纽北全球最速四门车”的好消息,并领衔发布了小米15系列手机、小米澎湃OS2、小米SU7Ultra量产版,以及小米平板7系列、小米手环9Pro、小......
  • 【云原生】云原生后端:监控与观察性
    目录引言一、监控的概念1.1指标监控1.2事件监控1.3告警管理二、观察性的定义三、实现监控与观察性的方法3.1指标收集与监控3.2日志管理3.3性能分析四、监控与观察性的最佳实践4.1监控工具选择4.2定期回顾与优化结论参考资料引言在现代云原生架构中,监控与......
  • 2007版cad安装不上缺少net3.5怎么办
    浏览器地址栏输入www.dnz9.com远程解决netframework问题如果在安装2007版CAD(如AutoCAD2007)时遇到缺少.NET组件的问题,可以按照以下步骤进行解决:一、检查并安装.NETFramework打开控制面板:点击“开始”按钮,选择“控制面板”。进入程序和功能:在控......
  • 未安装net无法安装cad2007安装不上怎么解决?
    未安装net无法安装cad2007安装不上怎么解决?若要顺利安装CAD2007,您首先需要确保您的计算机上已正确安装了.NETFramework。这一关键组件为软件提供了必要的运行环境,从而保证CAD2007能够顺畅运作。在开始安装CAD之前,请检查并安装所需的.NETFramework版本,以避免出现兼容性问题......
  • 【JavaSE】认识String类,了解,进阶到熟练掌握
    #1024程序员节|征文#下面就让博主带领大家一起解决心中关于String类的疑问吧~~~1.字符串构造:第一种和第二种(有一定的区别,在常量池上)publicstaticvoidmain(String[]args){//使用常量串构造Strings1="hello";System.out.println(s1);//直接newString对象S......
  • eslint配置文件eslintrc.js
    eslintrc.js是ESLint的配置文件,主要用于定义代码质量和风格规则。ESLint是一个流行的JavaScript和TypeScript代码静态分析工具,可以帮助开发者识别和修复潜在的代码问题,确保代码的一致性和质量。1.功能配置规则:在eslintrc.js中,你可以指定ESLint应该应用哪些......
  • Spring学习笔记_15——@Resource
    @Resource1.介绍@Resource注解是JSR250规范中提供的注解,主要作用就是通过JNDI技术查找依赖的组件并注入到类、字段和方法中来。默认情况下,不指定注解任何属性时,会默认按照byName的方式装配Bean对象,如果指定了name属性,没有指定type属性,则采用byName的方式装配Bean对象,如果......
  • 音频基础知识
    一、声音的几个物理概念1、振动声音是由物体的振动引起的一种物理现象。物体的振动使其四周的气压产生变化,这种忽强忽弱变化以波的形式向四周传播,当被人耳所接收时,我们就听见了声音。2、波形声音是由物体的振动产生的,这种振动引起了周围空气压强的振荡,我们就称这种振荡的......