线程终止

exit是危险的
如果进程中的任意一个线程调用了exit,那么整个进程终止。

不终止进程的退出方式
普通单个线程的退出方法,以下方法退出不会导致进程终止:
(1)从启动例程中返回,返回值是线程的退出码(return)。
(2)线程可以被同一进程的其他线程取消。
(3)线程调用pthread_exit(void *rval)函数,rval是退出码。

例子

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>void *thread_func(void *arg){char *num=(char *)arg;if(strcmp("1",num)==0){printf("new thread return\n");return (void *)1;}else if(strcmp("2",num)==0){printf("new thread pthread_exit\n");pthread_exit((void*)2);}else if(strcmp("3",num)==0){printf("new thread exit\n");exit(3);}return (void *)0;
}int main(int argc,char *argv[]){pthread_t ntid;int err;err=pthread_create(&ntid,NULL,thread_func,argv[1]);if(err!=0){printf("new thread create failed!\n");return 0;}pthread_join(ntid,NULL ); printf("main thread\n");return 0;}

运行结果

machine:~/Desktop/C/thread$ ./pthread_exit  1
new thread return
main threadmachine:~/Desktop/C/thread$ ./pthread_exit  2
new thread pthread_exit
main threadmachine:~/Desktop/C/thread$ ./pthread_exit  3
new thread exit

return和pthread_exit()的区别

应用场景推荐方法选择依据
线程入口函数正常返回return语法简洁,符合常规函数返回逻辑
子函数中终止线程pthread_exit()return仅返回上层函数,无法直接终止线程
主线程退出但不影响子线程pthread_exit()使用return会导致进程退出,从而强制终止所有子线程

线程连接

pthread_join()
1‌.函数原型‌:
int pthread_join(pthread_t tid, void **rval);

2‌.功能描述‌:
pthread_join函数用于等待指定线程结束,并以阻塞的方式执行。调用该函数的线程会一直阻塞,直到指定的线程tid调用pthread_exit、从启动例程返回或者被取消

3.参数说明‌:
tid:指定线程的ID,即要等待的线程的标识符。
rval:指向指针的指针,用于获取被等待线程的返回值。如果线程被取消,rval被置为PTHREAD_CANCELED。

4.返回值‌:
成功时返回0,失败时返回错误码。

‌5.线程状态‌:
调用pthread_join会使指定的线程处于可连接(joinable)状态等待回收。如果指定线程已经处于分离(detached)状态,那么调用pthread_join会失败。

注意每个线程‌只能被 join 一次‌。

6.显式回收:
对于处于 ‌joinable(可结合)状态‌的线程(默认创建的线程),必须‌主动调用 pthread_join() 函数‌来阻塞等待其终止并释放其占用的系统资源(如栈空间、线程描述符等)。
显式回收 = ‌对 joinable 线程调用 pthread_join()‌。 忽略此操作将导致资源持续占用,最终可能耗尽系统资源。

pthread_detach()
pthread_detach(pthread_t thread);

1.用于分离一个线程,使其处于分离状态。线程可以自己分离自己。
2.detach不会阻塞调用者,会立即返回。
3.不关心执行结果的后台任务,后台任务线程不需要与其他线程同步。
4.成功返回0,失败返回错误码。
5.线程终止时自动释放资源,无需其他线程回收。

注意:
调用限制:detach后的线程不能再join。

实践
1.阻塞方式,需要获取线程返回值或确认完成时用pthread_join(),主线程等待子线程完成工作。
2.不关心执行结果的后台任务用pthread_detach()。

线程取消

取消函数

int pthread_cancel (pthread_t tid)

功能:取消tid指定的线程。
返回值:成功返回0。

‌重要说明‌
1.取消只是发送一个请求,并不意味着等待线程终止。
2.发送成功也不意味着tid一定会终止。
一个线程到底会不会终止,具体得看它的取消状态。

取消状态
取消状态:就是线程对取消信号的处理方式,忽略或者响应。
‌1. 默认行为‌:
线程在创建时,默认会响应取消信号。

‌2. 设置取消状态‌:

pthread_setcancelstate(int state,int *oldstate)

使用pthread_setcancelstate(int state,int *oldstate)函数可以设置本线程对取消信号的反应。该函数有两个参数:
state:指定新的取消状态,可以是PTHREAD_CANCEL_ENABLE(缺省,收到信号后线程设为CANCELED状态)或PTHREAD_CANCEL_DISABLE(忽略取消信号继续运行)。
oldstate:如果不为NULL,则存入原来的取消状态以便恢复。

‌3. 取消状态的重要性‌:
在多线程编程中,正确设置线程的取消状态可以防止线程在不应该被终止的时候被取消,从而避免数据不一致或资源泄露等问题。

通过合理设置取消点(使用pthread_testcancel()函数),可以在安全的位置终止线程,进一步确保程序的稳定性和可靠性。

一个线程如果响应取消信号要进行终止了,那么什么时候会发生终止呢?是延迟终止还是立马终止?具体得要看取消类型。

取消类型
线程取消类型是指线程对取消信号的响应方式,主要有两种:
1.延时取消(PTHREAD_CANCEL_DEFERRED)‌(默认):
线程在收到取消信号后,会继续运行至下一个取消点再退出。这是线程创建时的默认取消类型。

‌2.立即取消(PTHREAD_CANCEL_ASYNCHRONOUS)‌:
线程在收到取消信号后,会立即执行取消动作并退出

可以通过pthread_setcanceltype函数来设置线程的取消类型,其函数原型为:

int pthread_setcanceltype(int type, int *oldtype);

1.type参数指定新的取消类型,取值为PTHREAD_CANCEL_DEFERRED或PTHREAD_CANCEL_ASYNCHRONOUS。
2.oldtype参数如果不为NULL,则函数会将原来的取消类型值存入该指针所指向的位置。
3.仅当取消状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出(延迟取消)和立即执行取消动作(退出)(立即取消)。

注意:
设置取消类型时,需确保线程的取消状态为Enable(可通过pthread_setcancelstate函数设置),否则取消类型设置将无效。

取消点
‌取消一个线程时,通常需要该线程的配合‌。线程在运行过程中会主动检查是否有取消请求,‌这些检查点被称为取消点‌。

包含取消点的常见函数和系统调用有:
‌pthread_join()‌:等待线程结束。
‌pthread_testcancel()‌:测试线程是否被取消。
‌pthread_cond_wait()‌ 和 ‌pthread_cond_timedwait()‌:条件变量等待。
‌sem_wait()‌:信号量等待。
‌sigwait()‌:等待信号。
‌write‌ 和 ‌read‌:文件读写操作。
printf();
‌大多数会阻塞的系统调用‌。

例子

#include <stdio.h>
#include <pthread.h>void *thread_func(void *arg){int stateval=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);if(stateval!=0){printf("set cancel state failed\n");}printf("new thread:set cancel disable\n");sleep(4);pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); //立马取消,无需等待特定的取消点。不设置默认就是延迟取消printf("set cancel enable\n"); //消息点1printf("I am new thread\n");  //消息点2return (void*)10;
}int main(int argc,char *argv[]){pthread_t ntid;void *rval;int err=pthread_create(&ntid,NULL,thread_func,NULL);if(err!=0){printf("thread create failed\n");return -1;}sleep(2);printf("main thread\n");int cval=pthread_cancel(ntid);if(cval!=0){printf("thread cancel failed\n");}pthread_join(ntid,&rval);printf("main thread\n");printf("cval is %d\n",cval);printf("rval is %d\n",(int)rval);  //返回-1:表示线程被取消return 0;}

1.默认的延时取消结果:

machine:~/Desktop/C/thread$ ./thread_cancel 
new thread:set cancel disable
main thread
set cancel enable
main thread
cval is 0
rval is -1

2.设置立即取消的结果:

machine:~/Desktop/C/thread$ ./thread_cancel 
new thread:set cancel disable
main thread
main thread
cval is 0
rval is -1

向线程发送信号

pthread_kill
用于向特定线程发送信号以实现线程间通信。
大部分的signal的默认动作是终止进程的运行,所以需要使用sigaaction()去抓信号并加上处理函数

函数原型‌
int pthread_kill(pthread_t thread, int sig);

‌参数说明‌
‌thread‌:指定目标线程的ID,该ID必须是通过pthread_create创建的合法线程ID。
‌sig‌:要发送的信号值,取值范围为0至63的整数值。特殊值0用于线程存活检测,不发送实际信号。

‌功能特点‌
1.当sig参数不为0时,向指定线程发送信号。若线程未处理该信号,则按信号的默认行为影响整个进程。也就是说,如果你给线程发送了SIGQUIT,但线程没有实现signal处理函数的话,则整个进程退出。
2.当sig参数为0时,仅执行线程有效性检测,不发送实际信号,用于判断线程是否存活。

‌注意事项‌
1.使用pthread_kill发送信号时,需确保线程内已正确实现信号处理函数,否则可能影响整个进程的运行。
2.信号处理函数是进程级全局生效的,不同线程不能定义独立的信号处理逻辑。
3.发送SIGKILL等可能导致进程级终止的信号时,需谨慎处理,以避免资源泄漏或进程异常终止。

‌应用场景‌
1.线程间通信:通过发送信号实现线程间的同步或事件通知。
2.线程状态检测:通过发送0信号判断线程是否存活。
3.异常处理:定向发送异常信号到监控线程,进行异常捕获和处理。

清除操作

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DeepSeek+WinForm串口通讯实战

前言 在现代软件开发中&#xff0c;串口通讯仍然是工业自动化、物联网设备和嵌入式系统的重要通信方式。随着.NET技术的发展&#xff0c;特别是.NET 5/.NET 6的跨平台能力&#xff0c;传统的WinForm应用现在可以通过现代UI框架实现真正的跨平台串口通讯。本文将深入探讨三种主…

针对数据仓库方向的大数据算法工程师面试经验总结

⚙️ 一、技术核心考察点 数据建模能力 星型 vs 雪花模型&#xff1a;面试官常要求对比两种模型。星型模型&#xff08;事实表冗余维度表&#xff09;查询性能高但存储冗余&#xff1b;雪花模型&#xff08;规范化维度表&#xff09;减少冗余但增加JOIN复杂度。需结合场景选择&…

Nuxt3 Cannot read properties of undefined (reading ‘createElement‘)

你遇到的 TypeError: Cannot read properties of undefined (reading createElement) 这个报错&#xff0c;通常是由于在 Nuxt3 或 Vue3 项目中&#xff0c;某些地方尝试访问 document.createElement 或类似 DOM API&#xff0c;但此时 document 还未定义&#xff08;比如在服务…

正则表达式匹配实现

直接上代码 using Microsoft.AspNetCore.Mvc; using System.Text.RegularExpressions;namespace SaaS.OfficialWebSite.Web.Controllers {public class RegController : Controller{public IActionResult Index(){return View();}[HttpPost]public IActionResult TestRegex([F…

API测试工具Parasoft SOAtest:应对API变化,优化测试执行

API频繁变更给测试工作带来诸多挑战&#xff0c;如手动排查变更影响耗时费力、测试用例维护繁琐易出错等。Parasoft SOAtest作为一款企业级API测试工具&#xff0c;通过自动扫描API接口、智能分析变更影响、优化测试&#xff0c;执行以及支持测试用例共享与版本控制等功能&…

mysql 数据库连接 -h localhost 和 -h 127.0.0.1 区别是什么

对于 mysql 数据库&#xff0c; 在 my.conf 中指定的client 端口是 3358&#xff0c;实际的mysql server 的端口监听在 3306&#xff0c; mysql -h localhost 可以居然可以连接成功&#xff1b; mysql -h 127.0.0.1 连接失败提示Can’t connect to MySQL server on 127.0.0.1&a…

Educational Codeforces Round 180 (Rated for Div. 2) A-D

A.Race 题目大意 给你两个x,y&#xff0c;终点会在二点之间随机出现,alice在点a&#xff0c;假设alice和bob有相同的速度&#xff08;距离更短者用时更少&#xff09;&#xff0c;问对于bob是否存在一点&#xff0c;无论终点是x还是y,他都能比alice更快到达 思路 如果alice在…

python requests post请求

在Python中&#xff0c;使用requests库进行POST请求是一种常见的操作&#xff0c;用于向服务器发送数据。下面是如何使用requests库进行POST请求的步骤&#xff1a; 安装requests库 如果你还没有安装requests库&#xff0c;可以通过pip安装&#xff1a; pip install requests…

Postman中设置定时自动运行接口测试

‌创建测试集合‌ 将需每日运行的接口组织到Collection中&#xff0c;并配置好测试脚本和断言。 ‌配置定时运行‌ 打开目标Collection → 点击 ‌Run‌ 按钮在Collection Runner页面底部选择 ‌Schedule runs‌关键配置&#xff1a; Frequency: Daily // 选择每日执行 Time…

multiprocessing.pool和multiprocessing.Process

在CPU密集型任务中&#xff0c;Python的multiprocessing模块是突破GIL限制的关键工具。multiprocessing.Pool&#xff08;进程池&#xff09;和multiprocessing.Process&#xff08;独立进程&#xff09;是最常用的两种并行化方案&#xff0c;但其设计思想和适用场景截然不同。…

容器技术技术入门与 Docker 环境部署

目录 一&#xff1a;Docker概述 1、 Docker的优势&#xff1a; &#xff08;1&#xff09;环境一致性 &#xff08;2&#xff09;隔离性 &#xff08;3&#xff09;资源高效 &#xff08;4&#xff09;便捷性和可扩展性 2、Docker容器与传统虚拟机的区别 3、Docker的应用…

Oracle获取执行计划之DBMS_XPLAN 技术详解1

在 Oracle 数据库的管理与优化工作中&#xff0c;深入了解 SQL 语句的执行计划是至关重要的一环。DBMS_XPLAN 包作为 Oracle 提供的强大工具&#xff0c;能够帮助数据库管理员&#xff08;DBAs&#xff09;和开发人员清晰地查看和分析 SQL 语句的执行计划&#xff0c;从而实现对…

【Python】VScode配置Python教程

文章目录 【Python】VScode配置Python教程下载Python安装插件解决乱码彻底运行vscode安装python库 【Python】VScode配置Python教程 前言&#xff1a; 当「Python 编程潜力」遇上「VSCode 开发神器」&#xff0c;会点燃怎样的效率革命&#xff1f;试想这样的场景&#xff1a;你…

PowerBI HtmlContent生成表格

假设有销量表: 1.PowerBI 导入 Html Content对象&#xff0c;并拖入报表 2.新建度量值: 度量值 VAR colCount DISTINCTCOUNT(销量[产品]) VAR ColumnHeaders "<tr><th styleborder:1px solid black; padding:5px; text-align:center; colspan"&col…

【人工智能与机器人研究】基于运动数据时空特征提取的人类运动片段分割方法

导读 动作示教方法是非专家用户对人形机器人进行控制的可靠形式&#xff0c;而对人类动作数据的运动分割与理解是其前提。利用现有方法对所捕获人类运动原始数据进行关键帧提取与运动分割时&#xff0c;由于数据特征不明确&#xff0c;导致难以准确定位运动起始帧、结束帧及分…

ARM内核之CMSIS

1.什么是CMSIS&#xff1f; CMSIS&#xff08;Cortex Microcontroller Software Interface Standard&#xff0c;Cortex微控制器软件接口标准&#xff09;提供Cortex-M内核与软件之间的接口&#xff0c;即用户可以通过这些统一的接口&#xff08;函数API&#xff09;去访问底…

嵌入式软件面经(二)Q: Modbus协议CRC校验的方式是什么?它有哪些优势?

Modbus协议使用的CRC&#xff08;循环冗余校验&#xff09;是一种用于确保数据通信完整性和准确性的差错检测方法。在Modbus RTU通信中&#xff0c;CRC校验过程清晰明确&#xff0c;且被广泛应用于工业通信场景。 一、Modbus协议的CRC校验流程 &#xff08;一&#xff09;CRC计…

glib-object 中G_DEFINE_TYPE 宏都作了什么?

author: hjjdebug date: 2025年 06月 25日 星期三 15:35:26 CST descrip: glib-object 中G_DEFINE_TYPE 宏都作了什么? 文章目录 1. 测试代码2 给出它的展开式.3.说说它都生成了什么?3.1. my_foo_get_type() 函数3.2. static GType my_foo_get_type_once(void)3.3. my_foo_cl…

Alembic迁移系统初始化实战教程

下面是一份结构清晰、步骤明确的 基于 Alembic Pydantic SQLAlchemy 的数据库迁移系统初始化教程&#xff0c;非常适合初次搭建项目或团队规范流程参考。 &#x1f680; Alembic SQLAlchemy Pydantic 项目数据库迁移初始化教程 本教程将指导你如何从零初始化 Alembic 迁移…

灰度发布怎么保证数据库一致的

注&#xff1a; 以下内容来源于deepseek答案&#xff0c;生产环境以实际情况为主&#xff01; 在灰度发布中保证数据库一致的最优解需要同时满足安全性、低复杂度和高可操作性。结合多年实战经验&#xff0c;以下是最推荐的黄金方案&#xff08;适用于90%以上场景&#xff09;&…