Linux应用:线程基础
线程介绍
进程是程序在操作系统里的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的一个执行单元,是 CPU 调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等。
POSIX 线程库(pthread)
在 C 语言中,通常使用 POSIX 线程库(pthread)来创建和管理线程。该库提供了一系列函数来操作线程,例如创建线程、等待线程结束、设置线程属性等。使用 pthread 库需要包含头文件 <pthread.h>,并且在编译时需要链接 -lpthread 库。
基本的线程操作函数
创建线程:pthread_create
#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
thread:指向 pthread_t 类型的指针,用于存储新创建线程的线程 ID。
attr:指向 pthread_attr_t 类型的指针,用于设置线程的属性。若为 NULL,则使用默认属性。
start_routine:指向线程执行函数的指针,该函数的返回值类型为 void *,参数类型为 void *。
arg:传递给线程执行函数的参数。
等待线程结束:pthread_join
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);
thread:要等待的线程的线程 ID。
retval:指向 void * 类型的指针,用于存储线程执行函数的返回值。
线程退出:pthread_exit
#include <pthread.h>void pthread_exit(void *retval);
retval:线程的返回值。
简单的 C 语言线程示例
#include <stdio.h>
#include <pthread.h>// 线程执行函数
void *thread_function(void *arg) {int *num = (int *)arg;printf("线程正在运行,接收到的参数是: %d\n", *num);pthread_exit(NULL);
}int main() {pthread_t thread_id;int number = 10;// 创建线程if (pthread_create(&thread_id, NULL, thread_function, &number) != 0) {perror("线程创建失败");return 1;}// 等待线程结束if (pthread_join(thread_id, NULL) != 0) {perror("等待线程结束失败");return 1;}printf("主线程继续执行\n");return 0;
}
编译命令:
gcc fs.cpp -lpthread

线程取消
pthread_cancel 函数
用于向指定线程发送取消请求,通常由主线程调用以取消子线程的执行。
#include <pthread.h>int pthread_cancel(pthread_t thread);
thread:要取消的线程的线程 ID。
返回值:若成功,返回 0;若出错,返回错误码。
pthread_setcancelstate 函数
用于设置线程的取消状态,即线程是否允许被取消
#include <pthread.h>int pthread_setcancelstate(int state, int *oldstate);
state:新的取消状态,有两个可选值:
PTHREAD_CANCEL_ENABLE:允许线程被取消(默认状态)。
PTHREAD_CANCEL_DISABLE:禁止线程被取消。
oldstate:指向整数的指针,用于存储线程原来的取消状态。若不需要保存原来的状态,可传入 NULL。
返回值:若成功,返回 0;若出错,返回错误码。
pthread_setcanceltype 函数
用于设置线程的取消类型,即线程在接收到取消请求后何时响应
#include <pthread.h>int pthread_setcanceltype(int type, int *oldtype);
type:新的取消类型,有两个可选值:
PTHREAD_CANCEL_DEFERRED:延迟取消,线程在接收到取消请求后,会在执行到取消点(如 pthread_testcancel、sleep、read、write 等函数)时才响应取消请求。
PTHREAD_CANCEL_ASYNCHRONOUS:异步取消,线程在接收到取消请求后,会立即响应取消请求。
oldtype:指向整数的指针,用于存储线程原来的取消类型。若不需要保存原来的类型,可传入 NULL。
返回值:若成功,返回 0;若出错,返回错误码。
代码示例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 子线程函数
void *thread_function(void *arg) {int oldstate, oldtype;// 设置线程允许被取消pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);// 设置线程为延迟取消类型pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);printf("子线程开始执行\n");// 模拟一些工作for (int i = 0; i < 10; i++) {printf("子线程正在工作: %d\n", i);sleep(1);// 检查取消点pthread_testcancel();}printf("子线程执行完毕\n");return NULL;
}int main() {pthread_t thread_id;// 创建子线程if (pthread_create(&thread_id, NULL, thread_function, NULL) != 0) {perror("线程创建失败");return 1;}// 主线程休眠3秒sleep(3);// 向子线程发送取消请求if (pthread_cancel(thread_id) != 0) {perror("取消线程失败");return 1;}printf("主线程已发送取消请求\n");// 等待子线程结束if (pthread_join(thread_id, NULL) != 0) {perror("等待线程结束失败");return 1;}printf("主线程继续执行\n");return 0;
}

异步取消
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 子线程函数
void *thread_function(void *arg) {int oldstate, oldtype;// 设置线程允许被取消pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);// 设置线程为异步取消类型pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);printf("子线程开始执行\n");int sum = 0;// 模拟长时间运行的任务while (1) {printf("子线程正在执行 sum = %d\n", sum);fflush(stdout); // 刷新输出缓冲区usleep(1000);sum += 10;}// 以下代码不会被执行到,因为线程会在收到取消请求时立即结束printf("子线程执行完毕\n");return NULL;
}int main() {pthread_t thread_id;// 创建子线程if (pthread_create(&thread_id, NULL, thread_function, NULL) != 0) {perror("线程创建失败");return 1;}// 主线程休眠2秒,让子线程有时间开始执行sleep(2);// 向子线程发送取消请求if (pthread_cancel(thread_id) != 0) {perror("取消线程失败");return 1;}printf("主线程已发送取消请求\n");// 等待子线程结束if (pthread_join(thread_id, NULL) != 0) {perror("等待线程结束失败");return 1;}printf("主线程继续执行\n");return 0;
}
实际上没有判断处理是哪里异步取消!!!

线程清理
pthread_cleanup_push
#include <pthread.h>void pthread_cleanup_push(void (*routine)(void *), void *arg);
功能:将一个清理处理程序压入线程的清理处理程序栈。当线程通过 pthread_exit 终止、被 pthread_cancel 取消或者执行 pthread_cleanup_pop 且参数为非零值时,会调用该清理处理程序。
参数:
routine:指向清理处理程序的函数指针,该函数接受一个 void * 类型的参数,并且没有返回值。
arg:传递给清理处理程序的参数。
pthread_cleanup_pop
#include <pthread.h>void pthread_cleanup_pop(int execute);
功能:从线程的清理处理程序栈中弹出一个清理处理程序。如果 execute 参数为非零值,则会调用该清理处理程序;如果为零,则不会调用该清理处理程序。
参数:
execute:一个整数,用于决定是否执行清理处理程序。非零值表示执行,零表示不执行。
代码示例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 清理处理程序
void cleanup_handler(void *arg) {printf("清理处理程序被调用,参数为: %s\n", (const char *)arg);
}// 子线程函数
void *thread_function(void *arg) {const char *message = (const char *)arg;// 压入清理处理程序pthread_cleanup_push(cleanup_handler, (void *)message);printf("子线程开始执行\n");// 模拟长时间运行的任务for (int i = 0; i < 5; i++) {printf("子线程正在工作: %d\n", i);sleep(1);}// 弹出清理处理程序,并执行它pthread_cleanup_pop(1);printf("子线程执行完毕\n");return NULL;
}int main() {pthread_t thread_id;const char *message = "Hello, Cleanup!";// 创建子线程if (pthread_create(&thread_id, NULL, thread_function, (void *)message) != 0) {perror("线程创建失败");return 1;}// 等待子线程结束if (pthread_join(thread_id, NULL) != 0) {perror("等待线程结束失败");return 1;}printf("主线程继续执行\n");return 0;
}
主要是保证即便子线程被取消了,该进行的操作还是可以顺利完成

pthread_detach
#include <pthread.h>
int pthread_detach(pthread_t thread);
参数:
thread:要分离的线程的线程 ID。
返回值:若成功,返回 0;若出错,返回错误码。
pthread_self
#include <pthread.h>pthread_t pthread_self(void);
参数:该函数没有参数。
返回值:返回调用该函数的线程的线程 ID,类型为 pthread_t。
代码演示
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 子线程函数
void *thread_function(void *arg) {// 获取当前线程的线程 IDpthread_t tid = pthread_self();printf("子线程(线程 ID: %lu)开始执行\n", (unsigned long)tid);// 模拟子线程工作sleep(3);printf("子线程(线程 ID: %lu)执行完毕\n", (unsigned long)tid);return NULL;
}int main() {pthread_t thread_id;// 创建子线程if (pthread_create(&thread_id, NULL, thread_function, NULL) != 0) {perror("线程创建失败");return 1;}// 获取主线程的线程 IDpthread_t main_tid = pthread_self();printf("主线程(线程 ID: %lu)创建了子线程\n", (unsigned long)main_tid);// 分离子线程if (pthread_detach(thread_id) != 0) {perror("分离线程失败");return 1;}printf("主线程(线程 ID: %lu)已分离子线程\n", (unsigned long)main_tid);// 主线程继续执行其他任务printf("主线程(线程 ID: %lu)继续执行其他任务\n", (unsigned long)main_tid);sleep(5);printf("主线程(线程 ID: %lu)结束\n", (unsigned long)main_tid);return 0;
}
子线程函数 thread_function:
调用 pthread_self 获取当前子线程的线程 ID 并打印。
模拟子线程执行 3 秒的任务。
任务完成后,再次打印线程 ID 表示执行完毕。
主线程:
创建子线程。
调用 pthread_self 获取主线程的线程 ID 并打印。
调用 pthread_detach 分离子线程。
主线程继续执行其他任务,模拟执行 5 秒。
最后打印主线程结束信息。

分离后的子线程会自己回收自己需要销毁的资源
进程和线程的区别
定义
进程:是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程都有自己独立的地址空间、内存、数据栈以及其他用于维护进程运行的资源。
线程:是进程中的一个执行单元,是程序执行的最小单位。线程共享所属进程的资源,如地址空间、打开的文件等,但有自己独立的栈空间和程序计数器等。
资源分配
进程:拥有独立的资源,包括内存空间、文件描述符、信号量等。不同进程之间的资源相互隔离,一个进程的资源不会被另一个进程直接访问,以保证进程的独立性和稳定性。
线程:共享所属进程的资源,多个线程可以访问进程中的同一变量、文件等资源。这使得线程之间的通信相对容易,但也需要注意资源访问的同步和互斥问题,以避免数据冲突和不一致性。
调度
进程:作为系统调度的基本单位,进程的调度由操作系统的调度算法决定。进程的切换需要保存和恢复大量的上下文信息,包括寄存器值、内存管理信息等,因此进程切换的开销较大。
线程:是程序执行的最小单位,也是操作系统进行调度的基本单位。由于线程共享进程的资源,线程切换时只需保存和恢复少量的上下文信息,如寄存器值和栈指针等,因此线程切换的开销较小,能更高效地进行并发执行。
并发性
进程:多个进程可以并发执行,操作系统通过调度算法在不同的进程之间切换 CPU 时间片,实现多个进程的并发运行。但进程间的并发粒度较大,进程之间的切换相对较慢。
线程:一个进程中的多个线程可以并发执行,它们可以同时访问进程的资源,并且可以在不同的 CPU 核心上同时运行,实现真正的并行。线程间的并发粒度较小,线程的创建、销毁和切换速度较快,能更细粒度地控制程序的执行流程,提高程序的并发性能。
独立性
进程:具有较高的独立性,一个进程的崩溃通常不会影响到其他进程(除了一些特殊情况,如共享内存导致的问题)。每个进程都有自己独立的地址空间和资源,相互之间的影响较小。
线程:线程的独立性相对较低,因为它们共享所属进程的资源。如果一个线程出现错误,如访问了非法的内存地址或导致进程崩溃,可能会影响到整个进程以及其他线程的运行。
通信
进程:进程间通信(IPC)需要通过专门的机制,如管道、消息队列、信号量、共享内存等。这些机制需要操作系统的支持,并且涉及到数据在不同进程地址空间之间的传递,相对较为复杂。
线程:由于线程共享进程的地址空间,线程之间的通信可以直接通过共享变量来实现,通信方式较为简单和高效。但需要注意在多线程环境下对共享变量的访问控制,以确保数据的一致性和正确性。
适用场景
进程:适用于需要高度独立性和稳定性的任务,如服务器程序中的多个服务进程,每个进程可以独立处理不同类型的请求,互不干扰。另外,在一些对资源隔离要求较高的场景,如不同用户的任务处理,也适合使用进程。
线程:适用于需要频繁进行并发操作且对资源共享要求较高的场景,如图形界面应用程序中,一个线程用于处理用户界面的更新,另一个线程用于执行后台任务,如文件下载或数据处理,通过线程间的协作可以提高程序的响应性和用户体验。同时,在一些高性能计算和并发处理的场景中,线程也能发挥其高效并发的优势。
相关文章:
Linux应用:线程基础
线程介绍 进程是程序在操作系统里的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的一个执行单元,是 CPU 调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文…...
ngx_conf_parse
配置文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024; }http {#include mime.types;#default_type appli…...
要创建一个基于Spring Boot、Thymeleaf、MyBatis Plus和MySQL的简单表格增删改查(CRUD)项目
文章目录 要创建一个基于Spring Boot、Thymeleaf、MyBatis Plus和MySQL的简单表格增删改查(CRUD)项目1. 创建Spring Boot项目2.项目配置2.1 依赖yml配置数据库表配置 3.代码实现3.1 实体类3.2 数据访问层3.3 服务层3.4 控制层3.5 Thymeleaf模板 要创建一…...
解决Cubemx生产的 .ioc文件不能外部打开的方法
正常来说,cubemx生成的文件会有图标 但是当图标白色的时候,无法通过直接点击这个文件进入cubemx 1.首先检查java环境是不是装的JAVA8,如果是的话进行第二步操作; 2.重新安装一次cubemx,在安装的时候选择为我安装&…...
在 Linux(Ubuntu / CentOS 7)上快速搭建我的世界 MineCraft 服务器,并实现远程联机,详细教程
Linux 部署 MineCraft 服务器 详细教程(丐版,无需云服务器) 一、虚拟机 Ubuntu 部署二、下载 Minecraft 服务端三、安装 JRE 21四、安装 MCS manager 面板五、搭建服务器六、本地测试连接七、下载樱花,实现内网穿透,邀…...
Transformer | 一文了解:缩放、批量、多头、掩码、交叉注意力机制(Attention)
源自: AINLPer(每日干货分享!!) 编辑: ShuYini 校稿: ShuYini 时间: 2025-3-27 更多:>>>>专注大模型/AIGC、学术前沿的知识分享! 引言 之前的文章:2万字长文!一文了解…...
原型验证后客户推翻原有需求,如何止损
原型验证后客户推翻原有需求时止损的有效方法包括:迅速评估影响范围、立即开展沟通确认、调整项目计划和资源配置、更新变更管理流程、协商成本分担机制。其中,迅速评估影响范围是关键,项目团队必须立即明确此次变更的具体影响,包…...
六、小白学JAVA-类和对象
1、什么是类和对象 人类---类:走路、说话、学习 人---对象:具体到某个人,就是对象,走路、说话、学习,每个人都是独特的人。 public class Person {String name;public void walk() {System.out.println("我会走…...
CMLINK APN 手动设置
以下是针对 CMLINK 的 APN设置 的详细指南,基于常见配置需求: CMLINK APN 手动设置参数 参数项值说明名称CMLINK (自定义)任意命名(如 CMLINK、CM Internet 等),建议使用ASCII字符,无特殊符号。APNcm.com …...
深入探索 Python 中的 asyncio:异步编程的利器
在当今的软件开发中,异步编程已经成为了提高程序性能和响应能力的重要手段之一。Python 作为一种广泛使用的编程语言,提供了强大的异步编程支持,而 asyncio 库则是其中的核心。本文将深入探讨 asyncio 的基本概念、使用方法以及一些高级特性&…...
STM32硬件IIC与OLED使用
OLED屏幕介绍 OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术 OLED显示…...
基于Spring Boot的电动车智能充电服务平台的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
十、JavaScript对象
一、对象 创建对象的方法有三种:字面量、new、构造函数。 1.利用字面量创建对象 花括号{}里面包含了表达这个具体事物(对象)的属性和方法 // 1.利用对象字面量创建对象{}// var obj {}; // 创建了一个空的对象var obj {uname: black,ag…...
FFmpeg开发学习:音视频封装
1.基本流程 1.输入参数 输出文件路径 char *output 视频编码参数 AVCodecParameters *video_par 音频编码参数 AVCodecParameters *audio_par 数据包 AVPacket *packets[] 2.封装流程 (1)创建输出的上下文AVFormatContext指针 AVFormatContext *out_fm…...
hackmyvm-reversteg
arp-scan -l nmap -sS -v 192.168.222.45 在源码中可以看到 根据下面的提示可以猜测117db0148dc179a2c2245c5a30e63ab0是一个图像文件 将图片下载到本地 隐写术 在两张图片上使用strings,发现有一些可打印的字符串 strings 117db0148dc179a2c2245c5a30e63ab0.jpg base64解码…...
UE4学习笔记 FPS游戏制作17 让机器人持枪 销毁机器人时也销毁机器人的枪 让机器人射击
添加武器插槽 打开机器人的Idle动画,方便查看武器位置 在动画面板里打开骨骼树,找到右手的武器节点,右键添加一个插槽,重命名为RightWeapon,右键插槽,添加一个预览资产,选择Rifle,根…...
考研408-数据结构完整代码 线性表的链式存储结构 - 单链表
单链表操作详解(C实现) 目录 单链表尾插法创建单链表头插法创建删除指定节点按值查找按序号查找插入节点完整代码示例注意事项总结 尾插法创建 #include<bits/stdc.h> using namespace std;typedef struct LNode {int data;struct LNode* next;…...
蓝桥杯经典题解:班级活动分组问题的深度解析与优化实现
目录 一、问题背景与描述 二、问题分析与核心思路 2.1 问题本质:统计与配对优化 2.2 关键观察 2.3 数学建模 三、算法设计与实现步骤 3.1 算法步骤 3.2 代码实现(Python) 3.3 优化点分析 四、关键细节与常见误区 4.1 细节处理 4.…...
设计模式(创建型)-建造者模式
定义 建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。该模式允许通过多个简单的步骤逐步构建出一个复杂的对象,用户只需指定复杂对象…...
RIP和OSPF的区别
文章目录 RIP(路由信息协议)和 OSPF(开放最短路径优先)是两种常见的动态路由协议,它们的主要区别如下:1. 协议类型2. 更新方式3. 路由计算算法4. 最大跳数5. 管理距离(AD)6. 认证机制…...
Git 之配置ssh
1、打开 Git Bash 终端 2、设置用户名 git config --global user.name tom3、生成公钥 ssh-keygen -t rsa4、查看公钥 cat ~/.ssh/id_rsa.pub5、将查看到的公钥添加到不同Git平台 6、验证ssh远程连接git仓库 ssh -T gitgitee.com ssh -T gitcodeup.aliyun.com...
遍历数组时,如何获取数组每个元素索引号
在 JavaScript 中,有多种方法可以在遍历数组时获取每个元素的索引号,下面为你介绍几种常用的方法: 1. 使用 for 循环 const array [apple, banana, cherry]; for (let i 0; i < array.length; i) {console.log(索引 ${i} 的元素是: ${…...
黑马点评项目
遇到问题: 登录流程 session->JWT->SpringSession->tokenRedis (不需要改进为SpringSession,token更广泛,移动端或者前后端分离都可以用) SpringSession配置为redis模式后,redis相当于分布式se…...
如何防御TCP洪泛攻击
TCP洪泛攻击(TCP Flood Attack)是一种常见的分布式拒绝服务(DDoS)攻击手段,以下是其原理、攻击方式和危害的详细介绍: 定义与原理 TCP洪泛攻击利用了TCP协议的三次握手过程。在正常的TCP连接建立过程中&a…...
【AVRCP】AVRCP核心术语解析
目录 一、协议核心术语:架构的基石 1.1 音视频控制协议簇(AVRCP 生态链) 1.2 数据传输协议(L2CAP 核心术语) 二、设备架构术语:角色与交互 2.1 设备角色模型(CT/TG 二元架构) …...
【弹性计算】异构计算云服务和 AI 加速器(四):FPGA 虚拟化技术
异构计算云服务和 AI 加速器(四):FPGA 虚拟化技术 🚀 FPGA(Field-Programmable Gate Array,现场可编程门阵列)是一种可重构的半导体芯片,允许用户根据需要动态配置硬件逻辑ÿ…...
Python爬虫如何检测请求频率?
在进行网络爬虫开发时,合理设置请求频率是确保爬虫稳定运行、避免被目标网站封禁的关键策略之一。以下是一些有效的方法和最佳实践,帮助你合理设置请求频率,确保爬虫的可持续性和稳定性。 一、了解速度限制的原因 网站对爬虫速度进行限制的…...
编译原理——自底向上语法优先分析
文章目录 自底向上优先分析概述一、自底向上优先分析概述二、简单优先分析法(一)优先关系定义(二)简单优先文法的定义(三)简单优先分析法的操作步骤 三、算法优先分析法(一)直观算符…...
nuxt3网站文章分享微信 ,QQ功能
1.安装 npm install qrcode --save-dev 2.组件使用 <div class"share"><div style"line-height: 69px; color: #fff;width: 100px;"><p style"text-align: center;">分享:</p></div><div click"shareToMi…...
智能任务分配:Python高并发架构设计
Python并发编程实战:多进程与多线程的智能任务分配策略 引言:突破性能瓶颈的关键选择 在CPU核心数量激增和I/O密集型应用普及的今天,Python开发者面临着一个关键抉择:如何通过并发编程充分释放硬件潜力?本文通过实测数…...
