linux---多线程
- 线程的基本概念
- 定义:在Linux中,线程是进程内部的一个执行单元,是进程的一个实体,它是CPU调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,如代码段、数据段、打开的文件、信号处理函数等,但每个线程都有自己独立的栈空间和程序计数器(PC)。
- 与进程的区别:
- 进程是资源分配的基本单位,每个进程都有独立的地址空间和系统资源。而线程是进程中的执行路径,共享进程的大部分资源,这使得线程间的通信和切换成本相对较低。
- 进程间的切换需要进行系统调用,涉及到用户态和内核态的切换,开销较大。线程切换主要是在用户态下进行,只需要保存和恢复少量的寄存器内容和栈指针,速度更快。
- 线程库的选择 - pthread库
- 简介:在Linux系统中,最常用的线程库是POSIX线程库(pthread)。它提供了一系列函数来创建、管理和同步线程。使用pthread库时,需要在编译时链接
-lpthread选项。
- 简介:在Linux系统中,最常用的线程库是POSIX线程库(pthread)。它提供了一系列函数来创建、管理和同步线程。使用pthread库时,需要在编译时链接
- 线程的创建 -
pthread_create函数- 函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); - 参数说明:
thread:这是一个指向pthread_t类型变量的指针,用于存储新创建线程的标识符。attr:这是一个指向pthread_attr_t类型的指针,用于设置线程的属性,如线程的栈大小、调度策略等。如果为NULL,则使用默认属性创建线程。start_routine:这是一个函数指针,指向线程的起始函数。线程创建成功后,会从这个函数开始执行。该函数的参数是一个void*类型的指针,返回值也是一个void*类型的指针。arg:这是传递给start_routine函数的参数,通过void*类型的指针传递,可以传递任何类型的数据,在start_routine函数内部需要进行适当的类型转换。
- 返回值:
- 成功时返回0,表示线程创建成功。
- 失败时返回一个错误码,并且不会创建线程。可以通过
strerror函数将错误码转换为对应的错误信息。
- 示例代码(创建一个简单的线程):
- 函数原型:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 线程执行的函数
void *thread_function(void *arg) {// 在这里编写线程要执行的任务printf("这是一个新线程。\n");// 线程结束时返回NULLreturn NULL;
}
int main() {pthread_t thread_id;int result;// 创建线程result = pthread_create(&thread_id, NULL, thread_function, NULL);if (result!= 0) {// 如果创建线程失败,打印错误信息perror("线程创建失败");return 1;}// 主线程继续执行其他任务,这里简单地等待新线程结束result = pthread_join(thread_id, NULL);if (result!= 0) {perror("等待线程结束失败");return 1;}printf("主线程继续执行,线程已结束。\n");return 0;
}
- 线程的终止 -
pthread_exit函数和其他方式-
pthread_exit函数:- 函数原型:
void pthread_exit(void *value_ptr); - 功能:用于显式地终止一个线程。当线程执行到
pthread_exit函数时,线程会立即终止,并将value_ptr指向的值返回给等待该线程结束的线程(如果有)。这个返回值可以通过pthread_join函数获取。

- 函数原型:
-
在
start_routine函数中return返回:- 线程执行的起始函数
start_routine执行return语句时,线程也会正常终止,返回值的处理方式和pthread_exit类似。
- 线程执行的起始函数
-
线程被其他线程取消(
pthread_cancel函数):- 函数原型:
int pthread_cancel(pthread_t thread); - 功能:一个线程可以通过
pthread_cancel函数来请求取消另一个线程。被取消的线程会在合适的时机(如在某些系统调用中或者在检查取消点时)终止。不过,线程可以通过设置一些属性来控制是否响应取消请求以及如何响应。
- 函数原型:
-
- 线程的等待 -
pthread_join函数- 函数原型:
int pthread_join(pthread_t thread, void **value_ptr); - 参数说明:
thread:要等待的线程的标识符。value_ptr:这是一个指向void*类型指针的指针,用于存储被等待线程的返回值(如果线程通过pthread_exit函数或者在start_routine函数中return返回了一个值)。如果不需要获取返回值,可以将这个参数设置为NULL。
- 返回值:
- 成功时返回0,表示成功等待线程结束并获取了返回值(如果需要获取)。
- 失败时返回一个错误码,并且不会正确等待线程结束。
- 函数原型:
- 线程的同步 - 互斥锁(Mutex)
- 基本概念:
- 互斥锁用于保护共享资源,防止多个线程同时访问和修改共享资源而导致数据不一致。互斥锁有两种状态:锁定和解锁。当一个线程获取了互斥锁(锁定状态)后,其他线程如果试图获取同一把互斥锁,就会被阻塞,直到该锁被释放(解锁状态)。
- 互斥锁相关函数:
pthread_mutex_init函数:用于初始化一个互斥锁。函数原型为int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);,其中mutex是指向pthread_mutex_t类型变量的指针,用于存储互斥锁,attr是指向互斥锁属性的指针,如果为NULL,则使用默认属性初始化。pthread_mutex_lock函数:用于获取(锁定)互斥锁。函数原型为int pthread_mutex_lock(pthread_mutex_t *mutex);,如果互斥锁已经被其他线程锁定,调用该函数的线程会被阻塞,直到互斥锁被释放。pthread_mutex_unlock函数:用于释放(解锁)互斥锁。函数原型为int pthread_mutex_unlock(pthread_mutex_t *mutex);,当一个线程完成对共享资源的访问后,应该及时释放互斥锁,以便其他线程可以获取。pthread_mutex_destroy函数:用于销毁互斥锁。函数原型为int pthread_mutex_destroy(pthread_mutex_t *mutex);,在互斥锁不再使用时,应该销毁它,释放相关资源。
- 示例代码(使用互斥锁保护共享资源):
- 基本概念:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 定义一个共享变量
int shared_variable = 0;
// 定义互斥锁
pthread_mutex_t mutex;
// 线程执行的函数
void *thread_function(void *arg) {int i;for (i = 0; i < 1000; ++i) {// 锁定互斥锁pthread_mutex_lock(&mutex);// 访问共享资源shared_variable++;// 解锁互斥锁pthread_mutex_unlock(&mutex);}return NULL;
}
int main() {pthread_t thread_id1, thread_id2;int result;// 初始化互斥锁result = pthread_mutex_init(&mutex, NULL);if (result!= 0) {perror("互斥锁初始化失败");return 1;}// 创建两个线程result = pthread_create(&thread_id1, NULL, thread_function, NULL);if (result!= 0) {perror("线程1创建失败");return 1;}result = pthread_create(&thread_id2, NULL, thread_function, NULL);if (result!= 0) {perror("线程2创建失败");return 1;}// 等待线程结束result = pthread_join(thread_id1, NULL);if (result!= 0) {perror("等待线程1结束失败");return 1;}result = pthread_join(thread_id2, NULL);if (result!= 0) {perror("等待线程2结束失败");return 1;}// 销毁互斥锁result = pthread_mutex_destroy(&mutex);if (result!= 0) {perror("互斥锁销毁失败");return 1;}printf("共享变量的值为: %d\n", shared_variable);return 0;
}
- 线程的同步 - 条件变量(Condition Variable)
- 基本概念:
- 条件变量用于在线程之间进行同步,它允许一个线程等待某个条件为真。通常与互斥锁一起使用,一个线程可以在满足某个条件时通知其他等待该条件的线程。
- 条件变量相关函数:
pthread_cond_init函数:用于初始化一个条件变量。函数原型为int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);,其中cond是指向pthread_cond_t类型变量的指针,用于存储条件变量,attr是指向条件变量属性的指针,如果为NULL,则使用默认属性初始化。pthread_cond_wait函数:用于让一个线程等待条件变量满足。函数原型为int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);,在调用该函数时,线程会释放已经获取的互斥锁mutex,然后进入等待状态,直到另一个线程通过pthread_cond_signal或者pthread_cond_broadcast函数唤醒它,并且在被唤醒后会重新获取互斥锁。pthread_cond_signal函数:用于唤醒一个等待条件变量的线程。函数原型为int pthread_cond_signal(pthread_cond_t *cond);,它会唤醒至少一个等待条件变量cond的线程。pthread_cond_broadcast函数:用于唤醒所有等待条件变量的线程。函数原型为int pthread_cond_broadcast(pthread_cond_t *cond);。pthread_cond_destroy函数:用于销毁条件变量。函数原型为int pthread_cond_destroy(pthread_cond_t *cond);,在条件变量不再使用时,应该销毁它,释放相关资源。
- 示例代码(使用条件变量和互斥锁实现线程同步):
- 基本概念:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 定义互斥锁和条件变量
pthread_mutex_t mutex;
pthread_cond_t cond;
// 共享变量,表示资源是否可用
int resource_available = 0;
// 线程1执行的函数,用于生产资源
void *thread1_function(void *arg) {// 模拟生产资源的过程// 这里简单地等待一段时间后生产资源sleep(2);// 锁定互斥锁pthread_mutex_lock(&mutex);resource_available = 1;// 发送信号,通知等待资源的线程pthread_cond_signal(&cond);// 解锁互斥锁pthread_mutex_unlock(&mutex);return NULL;
}
// 线程2执行的函数,用于消费资源
void *thread2_function(void *arg) {// 锁定互斥锁pthread_mutex_lock(&mutex);// 检查资源是否可用,如果不可用则等待while (!resource_available) {pthread_cond_wait(&cond, &mutex);}// 消费资源,这里简单地打印一条消息printf("资源已被消费。\n");// 解锁互斥锁pthread_mutex_unlock(&mutex);return NULL;
}
int main() {pthread_t thread_id1, thread_id2;int result;// 初始化互斥锁和条件变量result = pthread_mutex_init(&mutex, NULL);if (result!= 0) {perror("互斥锁初始化失败");return 1;}result = pthread_cond_init(&cond, NULL);if (result!= 0) {perror("条件变量初始化失败");return 1;}// 创建两个线程result = pthread_create(&thread_id1, NULL, thread1_function, NULL);if (result!= 0) {perror("线程1创建失败");return 1;}result = pthread_create(&thread_id2, NULL, thread2_function, NULL);if (result!= 0) {perror("线程2创建失败");return 1;}// 等待线程结束result = pthread_join(thread_id1, NULL);if (result!= 0) {perror("等待线程1结束失败");return 1;}result = pthread_join(thread_id2, NULL);if (result!= 0) {perror("等待线程2结束失败");return 1;}// 销毁互斥锁和条件变量result = pthread_mutex_destroy(&mutex);if (result!= 0) {perror("互斥锁销毁失败");return 1;}result = pthread_cond_destroy(&cond);if (result!= 0) {perror("条件变量销毁失败");return 1;}return 0;
}

相关文章:
linux---多线程
线程的基本概念 定义:在Linux中,线程是进程内部的一个执行单元,是进程的一个实体,它是CPU调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,如代码段、数据段、打开的文件、信号处理…...
【JavaEE初阶】线程 和 thread
本节⽬标 认识多线程 掌握多线程程序的编写 掌握多线程的状态 一. 认识线程(Thread) 1概念 1) 线程是什么 ⼀个线程就是⼀个 "执⾏流". 每个线程之间都可以按照顺序执⾏⾃⼰的代码. 多个线程之间 "同时" 执⾏着多份代码. 还…...
如何规避eBay账号被封的风险?原因与对策
ebay是全球知名的跨境电商平台之一,吸引了不少的商家入驻。然而随着平台规则的不断更新和完善,很多ebay商家在运营的过程中,会遇到账号被封禁的问题。那ebay账号被封的原因有哪些?本文将带来详细的分析,帮助商家保护…...
Word使用分隔符实现页面部分分栏
文章目录 Word使用分隔符实现页面部分分栏分隔符使用页面设置 Word使用分隔符实现页面部分分栏 分隔符使用 word中的分隔符: 前面不分栏,后面分栏(或前面分栏,后面不分栏),只需要在分隔位置处插入分隔符:“连续”即…...
Express (nodejs) 相关
Express 相关 长乐未央学习视频东哥 1. 安装 express-generator 脚手架,新建项目 执行命令 npm install express express-generator4 -g 同时安装 express,和 express 脚手架. npm install express express-generator4 -g通过 express 脚手架创建 express 项目 exp…...
【Harmony Next】多个图文配合解释DevEco Studio工程中,如何配置App相关内容,一次解决多个问题?
解决App配置相关问题列表 1、Harmony Next如何配置图标? 2、Harmony Next如何配置App名称? 3、Harmony Next如何配置版本号? 4、Harmony Next如何配置Bundle ID? 5、Harmony Next如何配置build号? 6、Harmony Next多语言配置在哪…...
台球助教平台开发球厅预约选择机制和助教匹配选择机制详细需求实例说明(第十四章)
以下是对台球助教系统相关功能的详细规划描述: 一、预约助教功能 二、选择球厅练球功能 三、选择陪练时间功能 四、下单订单支付功能 一、预约助教功能 助教信息展示 在专门的 “助教预约” 页面,以列表形式呈现所有可供预约的台球助教。每个助教条目…...
MyBatis通过注解配置执行SQL语句原理源码分析
文章目录 前置准备流程简要分析配置文件解析加载 Mapper 接口MapperAnnotationBuilder解析接口方法注解parseStatement 方法详解MapperBuilderAssistant 前置准备 创建一个mybatis-config.xml文件,配置mapper接口 <mappers><!--注解配置--><mapper…...
开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)综述
定义 开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)是一种目标检测任务,旨在检测和识别那些未在训练集中明确标注的物体类别。传统的目标检测模型通常只能识别有限数量的预定义类别,而OVOD模型则具有识别“开放词汇…...
PHP基础
PHP代码标记 标准标记:<?php ?> PHP注释 单行:// # 多行:/* */ 两种浏览器输出文本的方式:echo 和 print echo <?php header("Content-Type:text/html;charsetutf-8"); // 输出字符串 ec…...
启用WSL后,使用ssh通道连接ubuntu
Enjoy WSL 目的 启用wsl后,使用windows自带的powershell、cmd操作linux还是不太好使。以下介绍开启ssh通道,并保证能在ssh通道下,也能正常使用wsl中的win命令行,以及正常打开gui应用。 离线更新WSL,请跳转链接:离线…...
GMSSL的不同python版本
链接1(推荐) 这个使用的库,是gm ssl 3.1.1。为什么推荐?因为这个有C源码。 GitHub - GmSSL/GmSSL-Python: Python binding to the GmSSL library 链接2 这个使用的库,是gmssl 3.2.2。搜索3.2.2,找不到相…...
【数理统计】参数估计
文章目录 点估计矩估计法最大似然估计法 区间估计单个正态总体参数的区间估计均值 μ \mu μ 的区间估计方差 σ 2 \sigma^2 σ2 的区间估计 两个正态总体参数的区间估计(略)补充:单侧置信区间 点估计 矩估计法 【定义】设 X X X 是随机…...
ios 混合开发应用白屏问题
一、问题场景 项目业务中某个前端页面中使用了多个echart 组件来显示历史数据, 在反复切换到这个页面后,会出现白屏问题。 二、问题分析 0x116000ab0 - GPUProcessProxy::didClose: 0x116000ab0 - GPUProcessProxy::gpuProcessExited: reasonCrash 0x11…...
对分布式系统的理解以及redis的分布式实现
对分布式系统有哪些了解? 分布式系统是由多个独立的计算节点(通常是计算机或服务器)组成的系统,这些节点通过网络相互通信和协作,共同完成任务。分布式系统的设计旨在提供可扩展性、容错性和高可用性,适用于大规模的数据处理和服务场景。 1. 分布式系统的核心特点 分布…...
VS项目,在生成的时候自动修改版本号
demo示例:https://gitee.com/chenheze90/L28_AutoVSversion 可通过下载demo运行即可。 原理:通过csproject项目文件中的Target标签,实现在项目编译之前对项目版本号进行修改,避免手动修改; 1.基础版 效果图如下 部…...
【蓝桥杯】43699-四平方和
四平方和 题目描述 四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多 4 个正整数的平方和。如果把 0 包括进去,就正好可以表示为 4 个数的平方和。 比如: 502021222 712121222; 对于一个给定的正整数,可…...
我的“双胞同体”发布模式的描述与展望
当被“激情”晕染,重创标题、摘要探索“吸睛”。 (笔记模板由python脚本于2024年12月19日 15:23:44创建,本篇笔记适合喜欢编撰csdn博客的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Free:大咖免…...
flask_socketio 以继承 Namespace方式实现一个网页聊天应用
点击进入上一篇,可作为参考 实验环境 python 用的是3.11.11 其他环境可以通过这种方式一键安装: pip install flask3.1.0 Flask-SocketIO5.4.1 gevent-websocket0.10.1 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple pip list 详情如下&am…...
go mod tidy 命令
go mod tidy 是 Go 语言的命令,用于清理和更新 go.mod 和 go.sum 文件。它主要有以下功能: 移除未使用的依赖项:从 go.mod 文件中删除那些在代码中不再使用的依赖项。 添加缺失的依赖项:添加代码中使用但尚未记录在 go.mod 文件中…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
