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

深入理解多线程

一、线程基本概念

1、概述

线程是允许应用程序并发的一种机制。线程共享进程内的所有资源。

线程是调度的基本单位。

每个线程都有自己的 errno。

所有 pthread 函数均以返回 0 表示成功,返回一个正值表示失败。

编译 pthread 程序需要添加链接库(-lpthread)。

线程的主要优势在于,能够通过全局变量来共享信息。同时也引入一个问题,多个线程对临界资源的竞争。

2、线程终止方式

1、线程函数执行 return 语句并返回指定值。

2、线程调用 pthread_exit。

3、调用 pthread_cancel() 取消线程。

4、任意线程调用 exit(), 或者主线程执行 return 语句。

二、Pthreads 数据类型

在这里插入图片描述

三、线程接口

1、创建线程

#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

pthread_create() 创建线程通过调用带有 arg 参数的 start_routine 函数开始执行。

2、终止线程

#include <pthread.h>void pthread_exit(void *retval);

3、线程 ID

#include <pthread.h>// 获取当前线程 ID
pthread_t pthread_self(void);// 判断 2 个线程ID是否相等
int pthread_equal(pthread_t t1, pthread_t t2);

4、连接已终止的线程

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);

pthread_join 等待由 thread 标识的线程终止。

如果 pthread_join 传入一个之前已经连接过的线程 ID,将导致无法预知的行为。

默认情况下,线程是可连接的(join),也就是程序退出时,其他线程可以通过调用 pthread_join() 获取其返回状态。

5、线程分离

#include <pthread.h>int pthread_detach(pthread_t thread);

有时,我们不关心程序的返回状态,只是希望系统在线程终止时能够自动清理并移除。在这种情况下,可以调用 pthread_detach 并向 thread 参数传入指定线程的标识符,将该线程标记为处于分离状态。

线程可以通过调用 pthread_detach() 实现自行分离。

一旦线程处于分离状态,就不能再使用 pthread_join() 获取其状态,也无法使其重返可连接状态。

6、线程取消

#include <pthread.h>int pthread_cancel(pthread_t thread);

7、线程可取消性检查

#include <pthread.h>void pthread_testcancel(void);

8、清理函数

#include <pthread.h>void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);

9、向线程发送信号

#include <signal.h>int pthread_kill(pthread_t thread, int sig);
#include <signal.h>
#include <pthread.h>int pthread_sigqueue(pthread_t thread, int sig,const union sigval value);

10、操作线程信号掩码

#include <signal.h>int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);

四、线程属性

五、线程同步 - 保护共享变量的访问:互斥量

1、分配互斥量

1、静态分配

pthread_mutex_t mutex;

2、动态分配

#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2、销毁互斥量

#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);

3、加锁和解锁互斥量

#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

调用 pthread_mutex_lock() 锁定互斥量。如果互斥量当前处于未锁定状态,该调用将锁定互斥量并立即返回。如果互斥量处于锁定状态,pthread_mutex_lock() 调用会一直阻塞,直到该互斥量被解锁。

pthread_mutex_unlock() 解锁调用线程锁定的互斥量,以下行为均为错误:

1、对未锁定的互斥量进行解锁。

2、解锁其他线程锁定的互斥量。

4、互斥量死锁

5、互斥量属性

6、互斥量类型

1、PTHREAD_MUTEX_NORMAL

不具备死锁自检功能。

线程试图对已由自己锁定的互斥量加锁,则发生死锁。

互斥量处于未锁定状态,或由其他线程锁定,对其解锁会导致不确定的结果。

2、PTHREAD_MUTEX_ERRORCHECK

此类互斥量的所有操作都会执行错误检查。

可以作为调试工具,以发现程序在哪里违反了互斥量使用的基本原则。

3、PTHREAD_MUTEX_RECURSIVE

该互斥量维护一个锁计数器。当线程第一次取得互斥量时,会将锁定计数器置1,后续同一线程的每次加锁操作会递增锁定计数器的数值,而解锁操作则会递减计数器计数,只有锁计数器值降至0时,才会释放。

六、线程同步 - 通知状态的改变:条件变量

条件变量允许一个线程就某个共享变量(或其他共享资源)的状态变化通知其他线程。

条件变量总是结合互斥量使用。

所有线程都应该处理虚假的唤醒

条件变量并不保存状态信息,只是传递应用程序状态信息的一种通讯机制。发送信号时,若无任何线程在等待条件变量,这个信号也就不了了之。

1、分配条件变量

1、静态分配

pthread_cond_t cond;

2、动态分配

#include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2、销毁条件变量

#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);

3、通知条件变量

#include <pthread.h>// 至少唤起一个线程
int pthread_cond_signal(pthread_cond_t *cond);
// 唤起所有阻塞线程
int pthread_cond_broadcast(pthread_cond_t *cond);

4、等待条件变量

#include <pthread.h>int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

七、线程安全

1、可重入性

要诀:避免使用全局变量和静态变量。

2、一次性初始化

#include <pthread.h>int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;

3、线程特有数据

4、线程局部存储

附录一:多线程示例

1、main.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void* pthread_message_function(void *ptr);int main(int argc, char *argv[])
{pthread_t pthreadID1,pthreadID2;int ret = 0;char *message1 = "thread1";char *message2 = "thread2";/* 1、创建线程1 */ret = pthread_create(&pthreadID1,NULL,pthread_message_function,(void*)message1);if(ret != 0){printf("%s create fail!\r\n",message1);}else{printf("%s create sucess!\r\n",message1);}/* 2、创建线程2 */ret = pthread_create(&pthreadID2,NULL,pthread_message_function,(void*)message2);if(ret != 0){printf("%s create fail!\r\n",message2);}else{printf("%s create sucess!\r\n",message2);}/* 3、休眠一定时间,等待子线程结束 */sleep(10);printf("main thread exit\r\n");return 0;
}void* pthread_message_function(void *ptr)
{int i = 0;/* 分离线程 - 避免僵尸线程产生 */pthread_detach(pthread_self());/* 业务逻辑 */for (i; i<5; i++) {printf("%s thread: %d\n", (char *)ptr, i);sleep(1);}
}

2、makefile

a.out: main.cgcc main.c -o a.out -lpthread.PHONY : clean 
clean:rm -rf a.out

3、测试

[root@localhost pthread]# make
gcc main.c -o a.out -lpthread
[root@localhost pthread]# ls
a.out  main.c  makefile
[root@localhost pthread]# ./a.out 
thread1 create sucess!
thread2 create sucess!
thread2 thread: 0
thread1 thread: 0
thread2 thread: 1
thread1 thread: 1
thread2 thread: 2
thread1 thread: 2
thread2 thread: 3
thread1 thread: 3
thread2 thread: 4
thread1 thread: 4
main thread exit
[root@localhost pthread]# 

相关文章:

深入理解多线程

一、线程基本概念 1、概述 线程是允许应用程序并发的一种机制。线程共享进程内的所有资源。 线程是调度的基本单位。 每个线程都有自己的 errno。 所有 pthread 函数均以返回 0 表示成功&#xff0c;返回一个正值表示失败。 编译 pthread 程序需要添加链接库&#xff08;…...

华为OD机试题 - 英文输入法(JavaScript)

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解: 英文输入法题目输入输出示例一输入输出说明示例一输入输出Code…...

64 云原生容器化

文章目录 一、什么是rancher二、为什么使用rancher三、 Rancher与[k8s](https://so.csdn.net/so/search?q=k8s&spm=1001.2101.3001.7020)的关系及区别1、Rancher具有的优势三、rancher安装1、细部介绍四、图形化操作1、执行2、图形化操作1、进行客户机登录rancher2、Ranch…...

IronXL for .NET 2023.2.5 Crack

关于适用于 .NET 的 IronXL 在 C# 中阅读和编辑 Excel 电子表格&#xff0c;无需 MS Office 或 Excel Interop。 IronXL for .NET 允许开发人员在 .NET 应用程序和网站中读取、生成和编辑 Excel&#xff08;和其他电子表格文件&#xff09;。您可以读取和编辑 XLS/XLSX/CSV/TS…...

计算机组成原理|第一章(笔记)

目录第一章 计算机系统概论1.1 计算机系统简介1.1.1 计算机的软硬件概念1.1.2 计算机系统的层次结构1.1.3 计算机组成和计算机体系结构1.2 计算机的基本组成1.2.1 冯 诺伊曼计算机的特点1.2.2 计算机的硬件框图1.2.3 计算机的工作过程1.3 计算机硬件的主要技术指标1.3.1 机器字…...

[ vulnhub靶机通关篇 ] Empire Breakout 通关详解

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

IP定位离线库有什么作用?

IP离线是什么意思&#xff1f;我们以丢失手机为例来寻找它&#xff0c;现在手机都有IP定位功能&#xff0c;只要手机开通了IP定位&#xff0c;就能找到手机。iPhone定位显示离线一般是iPhone手机关机了或者iPhone手机中“查找我的iPhone”功能关闭了。如果手机在手中的话可以打…...

[C++]vector模拟实现

目录 前言&#xff1a; 1. vector结构 2. 默认成员函数 2.1 构造函数 无参构造&#xff1a; 有参构造&#xff1a; 有参构造重载&#xff1a; 2.2 赋值运算符重载、拷贝构造&#xff08;难点&#xff09; 2.3 析构函数&#xff1a; 3. 扩容 3.1 reserve 3.2 resize…...

DevOps实战50讲-(2)Jenkins配置

1. Docker镜像方式安装拉取Jenkins镜像docker pull jenkins/jenkins编写docker-compose.ymlversion: "3.1" services:jenkins:image: jenkins/jenkinscontainer_name: jenkinsports:- 8080:8080- 50000:50000volumes:- ./data/:/var/jenkins_home/首次启动会因为数据…...

LC-1599. 经营摩天轮的最大利润(贪心)

1599. 经营摩天轮的最大利润 难度中等39 你正在经营一座摩天轮&#xff0c;该摩天轮共有 4 个座舱 &#xff0c;每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱&#xff0c;但每次轮转都需要支付一定的运行成本 runningCost 。摩天轮每次轮转都恰好转动 1 / 4 周。…...

Umi使用百度地图服务

需求描述 需要在前端页面中使用地图定位功能&#xff0c;所以在前端umi项目中使用百度地图服务&#xff0c;由于umi项目默认没有入口的html文件&#xff0c;所以无法通过常规的在head中加入外链js的方式使用 百度ak zyqeLCzvQPCCNImRu9yRGOqWlEUicxxGreact使用百度api 链接:…...

js中getBoundingClientRect()方法

getBoundingClientRect()返回值是一个 DOMRect 对象&#xff0c;是包含整个元素的最小矩形&#xff08;包括 padding 和 border-width&#xff09;。该对象使用 left、top、right、bottom、x、y、width 和 height 这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了 …...

Unity记录2.2-动作-动画、相机、Debug与总结

文章首发及后续更新&#xff1a;https://mwhls.top/4453.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 汇总&#xff1a;Unity 记录 摘要&#xff1a;重写了动画触…...

分享十个前端Web3D可视化框架附地址

Three.js&#xff1a;Three.js是一个流行的3D库&#xff0c;提供了大量的3D功能&#xff0c;包括基本几何形状、材质、灯光、动画、特效等。它是一个功能强大、易于使用的框架&#xff0c;广泛用于Web3D可视化应用程序的开发。Three.js&#xff1a;https://threejs.org/Babylon…...

基于WSL2和Clion搭建Win下C开发环境

系列文章目录 一、基于WSL2和Clion搭建Win下C开发环境 二、make、makeFile、CMake、CMakeLists的使用 三、全面、详细、通俗易懂的C语言语法和标准库 文章目录系列文章目录前言WSL2安装WSL常用命令VSCode连接WSLroot密码以systemd启动配置sshClion结语前言 Win下C语言开发环境…...

考研第一天,汤家凤基础班,连续与极限复习笔记

函数连续极限性质保号性证明极值点&#xff1a;夹逼准则二项式展开根号下&#xff0c;大于一&#xff0c;小于一的讨论直接放缩求和分子分母齐次&#xff0c;且分母大一次&#xff0c;用积分单调有界存在极限几个重要的切线放缩证明有界&#xff0c;然后放缩求单调证明有界&…...

聊一聊代码重构——关于变量的代码实践

提炼变量 其目标是将一个复杂表达式或语句分解成更小的部分&#xff0c;并将其存储在变量中。提高代码可读性和复用性 复杂的表达式 有些时候为了方便我们会把业务处理的逻辑写在一起&#xff0c;如果参与处理的内容较多时我们就会创造出一个非常长且难以理解的表达式。当其他…...

Spring之基于注解方式实例化BeanDefinition(1)

最近开始读Spring源码&#xff0c;读着读着发现里面还是有很多很好玩的东西在里面的&#xff0c;里面涉及到了大量的设计模式以及各种PostProcessor注入的过程&#xff0c;很好玩&#xff0c;也很复杂&#xff0c;本文就是记录一下我学习过程中的主干流程。 在开始我们源码解读…...

【STM32】入门(十四):FreeRTOS-任务

1、简述 FreeRTOS应用程序由一组独立的任务构成。 在任何时间点&#xff0c;应用程序中只能执行一个任务&#xff0c;FreeRTOS调度器负责决定所要执行的任务。 每个任务在自己的上下文中执行&#xff0c;不依赖于系统内的其他任务或 FreeRTOS的调度器本身。 FreeRTOS调度器负责…...

apscheduler 的基本介绍和使用

APScheduler有四大组件&#xff1a; 1、触发器 triggers &#xff1a; 触发器包含调度逻辑。每个作业都有自己的触发器&#xff0c;用于确定下一个任务何时运行。除了初始配置之外&#xff0c;触发器是完全无状态的。 有三种内建的trigger: &#xff08;1&#xff09;date: 特定…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...