pthread多线程: 创建最简单的线程

news2025/1/17 0:22:15

文章目录

    • 1. 目的
      • 1.1 不使用 Pthread 的情况
      • 1.2 使用 Pthread 的情况
      • 1.3 使用 Pthread 的好处
    • 2. Pthread 创建线程的 API
      • 2.1 环境
      • 2.2 `pthread_create()`
      • 2.3`pthread_join()`
    • 3. 创建最简单的线程
      • 3.1 要点
      • 3.2 代码
    • 4. 创建多个子线程
      • 4.1 要点
      • 4.2 代码
    • 5. 总结

在这里插入图片描述

1. 目的

Pthread 提供了 Linux / MacOSX 等系统下的一套多线程 API。使用多线程可以用于提升 CPU 利用率, 加速任务执行等。

1.1 不使用 Pthread 的情况

如果要使用多线程, 但是又不使用 Pthread, 我只能想到如下几种情况:

  1. 限定在 Windows 操作系统上,使用 Windows 的那一套多线程 API
  2. 使用 std::thread, 坚定的 modern C++, pure C++ 信仰
  3. 有一套封装好了的 API, 能支持当前系统, 例如封装了 Pthread 和 Windows thread, 甚至封装了 std::thread

1.2 使用 Pthread 的情况

实际上 Pthread 在非常多的 操作系统 x 编译器 x 硬件平台 组合条件下可以使用:

  • Linux x64 环境: 例如服务端编程,搞Web后端网络开发的
  • 深度学习加速,当然可能 openmp 也基本够用
  • Android 和 TDA4 这样的嵌入式设备上,对应到手机、车载两大消费者平台

1.3 使用 Pthread 的好处

使用 Pthread 还有额外的好处:

  • 能使用 std::thread, 大概率也能使用 Pthread,Windows 上有 Windows-Pthreads 库可以使用
  • Pthread 是 C 接口, 纯 C 环境仍然可以使用
  • Pthread 的例子很多, 开源代码也很多,甚至可能比 std::thread 的资料和例子多不止一倍

以上,是我学习使用 Pthread 的主要原因。

2. Pthread 创建线程的 API

2.1 环境

使用 ubuntu 22.04。它自带的 man 可以查询 pthread 的 API。

2.2 pthread_create()

man pthread_create
PTHREAD_CREATE(3)                                                 Linux Programmer's Manual                                                PTHREAD_CREATE(3)

NAME
       pthread_create - create a new thread

SYNOPSIS
       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Compile and link with -pthread.

2.3pthread_join()

这个API用于在当前线程等待子线程的结束。

PTHREAD_JOIN(3)                                                   Linux Programmer's Manual                                                  PTHREAD_JOIN(3)

NAME
       pthread_join - join with a terminated thread

SYNOPSIS
       #include <pthread.h>

       int pthread_join(pthread_t thread, void **retval);

       Compile and link with -pthread.

3. 创建最简单的线程

3.1 要点

何为最简单?能省则省, 能用默认就用默认。换言之使用最小必要条件创建一个子线程。

要点:

  • 子线程需要执行一个函数,需要实现这个函数 f (命名就很简洁)
  • 函数 f 需要返回 void* 类型
  • 函数 f 需要传入 void* 类型参数
  • 创建线程, 需要调用 pthread_create() 函数
  • 主线程需要等待线程结束,调用 pthread_join() 函数
  • 只创建一个子线程

3.2 代码

按如上要点很容易写出如下实现:
simplest.cpp

//
// 最简单的 pthread 创建线程的例子: 创建一个线程。线程参数和线程属性都用NULL
//

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

// 1. 线程函数返回值, 必须是 void*
// 2. 线程函数参数, 必须只有一个, 类型必须是 void*
void* f(void*)
{
    printf("This is thread function\n");
    return NULL;
}

int main()
{
    pthread_t t; // 3. 创建线程对象变量
    pthread_create(&t, NULL, f, NULL); // 4. 创建线程: 传入线程对象(参数1), 传入线程函数(参数3)。

    pthread_join(t, NULL); // 等待线程结束

    return 0;
}

编译并运行:

zz@Legion-R7000P% clang++ simplest.cpp 
zz@Legion-R7000P% ./a.out             
This is thread function

可以看到, 函数 f 被执行, 而 f 并不是按常规的 f() 方式显式调用,而是一种回调(callback)方式调用的。

4. 创建多个子线程

4.1 要点

基于前一节的代码,这次创建4个线程。创建线程、等待子线程结束的两段代码,各自用 for 循环包裹起来即可实现。

4.2 代码

multiple_threads.cpp:

//
// 创建多个线程。线程属性和线程参数仍然用NULL。
//

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

void* hello(void*)
{
    printf("This is hello\n");
    return NULL;
}

int main()
{
    const int N = 4;
    pthread_t t[N];
    for (int i = 0; i < N; i++)
    {
        pthread_create(&t[i], NULL, hello, NULL);
    }
    
    for (int i = 0; i < N; i++)
    {
        pthread_join(t[i], NULL);
    }

    return 0;
}

编译并运行:

zz@Legion-R7000P% clang++ multiple_threads.cpp 
zz@Legion-R7000P% ./a.out 
This is hello
This is hello
This is hello
This is hello

可以看到, 输出了4句相同的 This is hello, 说明确实运行了4次 f 函数, 而且主线程并没有显式调用 f(), 而是一种回调方式, 通过子线程来实现的调用。

5. 总结

这里的例子很简单, 说是简陋也不为过:

  • 参数是 NULL,没有传递有效参数
  • 各个线程之间独立, 没有展示互相依赖的情况
  • 主线程等待子线程结束, 没有考虑不需要等待的情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/557160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理-存储系统-基本概论及组成

目录 一、存储器的层次化结构 二、存储器分类 存储介质 存取方式 信息可改性 三、性能指标 四、主存储器基本组成 基本的的半导体元件及原理 存储芯片的基本原理 一、存储器的层次化结构 二、存储器分类 存储介质 半导体存储器(主存&#xff0c;cache)、磁表面存储器(…

基于SpringBoot的SSMP的整合案例

基于SpringBoot的SSMP的整合案例 简单介绍模块创建创建实体类导入Mybatis-plus和druid的配置文件使用junit测试查询方法MP分页查询按照条件进行查询业务层Service开发业务层Service快速开发表现层开发表现层 实现分页查询表现层消息一致性的处理查询所有书本信息添加书本删除操…

TensorFlow巨浪中的巨人:大数据领域的引领者 TensorFlow实战【上进小菜猪大数据系列】

上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。欢迎订阅本专栏&#xff01; 大数据时代的到来带来了海量数据的处理和分析需求。在这个背景下&#xff0c;TensorFlow作为一种强大的深度学习框架&#xff0c;展现了其在大数据领域…

fastreport使用教程(fastreport报表编辑器)

除了库本身&#xff0c;FastReport.Net还包括单独的程序 – Designer和Viewer。 如您所知&#xff0c;第一个用于创建和编辑报表模板。它具有报表预览模式&#xff0c;您可以从中查看报表&#xff0c;将其导出为所需的数据格式并将其发送到打印。 Viewer用于以fpx预览格式查看报…

清华p-tuning | GPT也能做NLU?清华推出p-tuning方法解决GPT系列模型fine-tuning效果比BERT差问题

一、概述 title&#xff1a;GPT Understands, Too 论文地址&#xff1a;https://arxiv.org/abs/2103.10385 代码&#xff1a;https://github.com/THUDM/P-tuning 1.1 Motivation GPTs模型利用传统的fine-tuning技术在NLU任务上效果比较差&#xff0c;比同等量级的BERT效果…

2023/5/22总结

继承 继承是面向对象三大特征之一。可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;追加属性和方法。 如图&#xff1a; 在上面的图片中&#xff0c;dog和cat都继承了Animal类&#xff0c;所以dog和cat都可以称为Animal的子类或者派生类&…

chatgpt赋能Python-python_dng

Python DNG&#xff1a;开启更高效的数据处理之路 什么是Python DNG&#xff1f; Python DNG&#xff08;Data NumPy Generator&#xff09;是一种基于Python的高效数据生成器&#xff0c;可以加速数据处理和分析的过程。它基于Numpy数组操作和并行计算思想&#xff0c;可以快…

C++详解NOI题:[NOIP2021] 报数

文章目录 前言一、题目二、暴力解题步骤&#xff08;50分&#xff09;三、打表防坑解题&#xff08;100分&#xff09;总结 前言 受不了CSDN每日一练的在线竞赛系统了&#xff0c;bug多就算了&#xff0c;勉强能用&#xff0c;可那些题目的神描述&#xff0c;到处是错。所以找…

前端面试知识点总结

前言&#xff1a; 博主突击两个月八股拿到美团&#xff08;基础研发&#xff09;&#xff0c;腾讯&#xff08;IEG&#xff09;&#xff0c;百度&#xff08;搜索部门&#xff09;暑期实习offer call&#xff0c;这是我学习过程中整理的前端知识点&#xff0c;内容有些多&#…

【13900k】i9 核显升级驱动

这里写自定义目录标题 官方的助手不能用显卡控制中心提示最新的更新搜索显卡 intel uhd graphics 770 手动下载安装自定义音频为啥也要卸载&#xff1f;新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片…

网络编程——嵌入式(驱动)软开基础(六)

1、简述TCP三次握手的过程。 (1)第一次握手:客户端创建传输控制块,然后向服务器发出连接请求报文(将标志位SYN置1,随机产生一个序列号seq=x),接着进入SYN-SENT状态。 (2)第二次握手:服务器收到请求报文后由SYN=1得到客户端请求建立连接,回复一个确认报文(将标志…

进程启动后到加载Activity的流程源码解析(基于安卓版本28)

文章目录 源码解析总体时序图关键类解析ActivityThreadApplicationThreadInstrumentationClientTransactionActivityStackSupervisorActivityRecord梳理概述源码流程梳理 源码解析 总体时序图 关键类解析 只针对流程中用到的关键类进行解析。 ActivityThread 注意其父类是&…

ES6升级之路:探究模板字符串、startsWith()方法和endsWith()方法、repeat()等新特性。

模版字符串 ES6新增的创建字符串的方式,使用反引号定义 示例 <script>// 1.模板字符串可以解析变量 ${}显示变量的值let name 张三;let sayHello HEllo,我的名字叫${name};console.log(name);console.log(sayHello);let result {name: "zhangsan",age: 20…

Java【TCP 协议2】确认应答、超时重传机制

文章目录 前言一、确认应答1, 什么是确认应答2, 序列号和确认应答号 二、超时重传1, 什么是超时重传 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系…

python基础(循环语句 while循环、break、continue,字符格式化,运算符)

1. while循环 【1】语法&#xff1a; while 条件:.........举例&#xff1a; print("123") while 条件:......... print(456)【2】循环语句的基本使用 示例1&#xff1a; print("开始") while True:print("hello world") print("结束&…

约瑟夫问题的环形链表实现[Java]

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;…

(全网最详细攻略)【Crypto++】在Visual studio2022中运行Cryptopp

文章目录 前言一、Cryptopp是什么&#xff1f;1. Cryptopp&#xff08;CRYPTO&#xff09;官方文档wiki 二、下载Cryptopp2. Crypto下载地址3. 下载PEM包 三、在VS2022中使用Cryptopp库4. 处理crypto源文件5. 在VS2022项目中使用crypto库 四、运行代码后一些关于c的错误总结 前…

单片机--中断实验练习

【1】实验要求&#xff1a; STM32上电LED&#xff08;PB0&#xff09;灯亮 &#xff0c;当检测到按键&#xff08;PA8&#xff09;按下时处理中断事件&#xff0c;变量i 扩展&#xff1a;知识点 响应优先级->在两个中断同时触发时&#xff0c;且这两个中断的优先级相同&a…

SpringBootWeb入门

1. SpringBootWeb快速入门 1.1 需求 需求&#xff1a;基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求/hello后&#xff0c;给浏览器返回字符串 “Hello World ~”。 1.2 开发步骤 第1步&#xff1a;创建SpringBoot工程项目 第2步&#xff1a;定义HelloCon…

chatgpt赋能Python-python_docx_目录

简介 Python是一种非常优秀的编程语言&#xff0c;主要用于数据分析、机器学习、人工智能等领域。在这些领域中&#xff0c;常常需要使用文档处理相关的工具&#xff0c;例如Microsoft Word。在使用Python编程的过程中&#xff0c;文档处理是非常常见的操作&#xff0c;因此Py…