当前位置: 首页 > 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: 特定…...

深度学习入门:基于cv_unet_image-colorization的Python实战项目

深度学习入门&#xff1a;基于cv_unet_image-colorization的Python实战项目 你是不是觉得深度学习听起来很高深&#xff0c;光是那些复杂的数学公式和框架名字就让人望而却步&#xff1f;别担心&#xff0c;今天我们就用一个特别有意思的项目&#xff0c;带你从零开始&#xf…...

Autosar最小系统搭建避坑指南:从Det到BswM,那些容易忽略的模块依赖与自动修复技巧

Autosar最小系统搭建避坑指南&#xff1a;从Det到BswM&#xff0c;那些容易忽略的模块依赖与自动修复技巧 在Autosar工程实践中&#xff0c;搭建最小系统往往是开发者面临的第一个实质性挑战。不同于简单的"Hello World"式验证&#xff0c;一个真正可运行的Autosar最…...

EcomGPT电商大模型实战案例:同一商品生成Amazon/Temu/Shopee三平台差异化文案

EcomGPT电商大模型实战案例&#xff1a;同一商品生成Amazon/Temu/Shopee三平台差异化文案 1. 项目背景与价值 跨境电商卖家经常面临一个痛点&#xff1a;同一个商品需要在不同平台上架&#xff0c;但每个平台的文案风格和用户偏好完全不同。传统方法需要人工针对每个平台单独…...

小白友好!DeepSeek-R1-Distill-Qwen-1.5B一键部署对话应用指南

小白友好&#xff01;DeepSeek-R1-Distill-Qwen-1.5B一键部署对话应用指南 1. 为什么选择这个模型&#xff1f; DeepSeek-R1-Distill-Qwen-1.5B是一款特别适合个人开发者和中小企业使用的轻量级AI对话模型。它最大的特点就是"小而强"——虽然体积小到能在手机上运行…...

别再瞎猜了!手把手教你用示波器看STM32晶振波形(附常见不起振原因排查)

嵌入式工程师必备技能&#xff1a;用示波器精准诊断STM32晶振故障 第一次焊接完STM32开发板&#xff0c;下载程序后却发现系统毫无反应——这种场景对嵌入式开发者来说再熟悉不过。当所有软件检查都无果时&#xff0c;硬件层面的晶振问题往往成为罪魁祸首。晶振如同嵌入式系统的…...

从零开始:用Ollama部署Qwen2.5-VL,打造你的私人图片助手

从零开始&#xff1a;用Ollama部署Qwen2.5-VL&#xff0c;打造你的私人图片助手 1. 引言&#xff1a;为什么选择Qwen2.5-VL&#xff1f; 在当今多模态AI快速发展的时代&#xff0c;能够同时理解图像和文本的模型变得越来越重要。Qwen2.5-VL作为Qwen家族的最新成员&#xff0c…...

Z-Image-Turbo_Sugar脸部Lora效果对比:Euler a vs DPM++ 2M SDE生成质量评测

Z-Image-Turbo_Sugar脸部Lora效果对比&#xff1a;Euler a vs DPM 2M SDE生成质量评测 1. 模型介绍与部署准备 Z-Image-Turbo_Sugar脸部Lora是一个专门针对甜美风格人像生成的AI模型&#xff0c;基于Z-Image-Turbo的Lora版本进行优化。这个模型特别擅长生成具有"纯欲甜妹…...

用STM32CubeMX和TensorFlow Lite,手把手教你给STM32F4部署一个“数字大小判断”AI模型(附完整Python训练代码)

STM32F4实战&#xff1a;从零构建数字分类AI模型的全流程解析 当嵌入式系统遇上人工智能&#xff0c;会擦出怎样的火花&#xff1f;本教程将带你完整实现一个运行在STM32F407开发板上的简易AI模型——它能准确判断输入数字是否小于24。这个看似简单的任务背后&#xff0c;蕴含着…...

OpenClaw隐私方案:Qwen2.5-VL-7B本地处理医疗影像数据

OpenClaw隐私方案&#xff1a;Qwen2.5-VL-7B本地处理医疗影像数据 1. 为什么医疗影像需要本地化处理 去年我在帮一家牙科诊所设计AI辅助诊断系统时&#xff0c;遇到了一个棘手问题&#xff1a;他们的X光片包含患者面部特征和牙科记录&#xff0c;直接上传到公有云存在隐私风险…...

深入解析CryptoJS:AES加密与解密在前端安全传输中的实战应用

1. 为什么前端需要加密传输&#xff1f; 想象一下这样的场景&#xff1a;用户在登录页面输入账号密码&#xff0c;点击提交按钮后&#xff0c;这些敏感信息会以明文形式在网络中传输。如果被中间人截获&#xff0c;后果不堪设想。这就是为什么我们需要在前端对敏感数据进行加密…...