[Linux系统编程]线程概念,三级映射,线程操作函数

news2024/10/23 18:00:16

一.线程概念

线程概念:
进程:有独立的 进程地址空间。有独立的pcb。
进程是分配资源的最小单位。
线程:没有独立的进程地址空间。有独立的pcb。
进程是cup执行的最小单位。
线程有线程id和线程号,线程id是用于进程内部标识线程的属性,而线程号是用于cpu标识执行单位的属性。
-
-Linux内核 实现线程的原理如下
-在这里插入图片描述
线程之间的共享与非共享关系
线程共享:
独享 栈空间(内核栈、用户栈),每个线程有独立的栈帧
共享 全局区,代码区,堆区 ./text. /data ./rodata ./bsss heap —> 共享【全局变量】

二. 三级映射(三级页表机制)

进程地址空间内部在经过MMU将数据映射到内存时,要经过三级页表查询逻辑地址映射到的实际物理地址,三级页表存在于进程的pcb中,对于线程来说,虽然pcb各自独立,但pcb中的三级页表是相同的。
在这里插入图片描述

三.线程操作函数

线程id类型: pthread_t

1.pthread_t pthread_self( ); 获取线程id。
返回值:线程id
出错返回:错误的error码。可以用 printf(strerror(ret))打印错误信息;

2.int pthread_create(pthread_t* tid, const pthread_attr_t* attr, 回调函数, void* arg);创建子线程。

参1:传出参数,表新创建的子线程 id
参2:线程属性。传NULL表使用默认属性。
参3:子线程回调函数。创建成功,ptherad_create函数返回时,该函数会被自动调用。void* (void*) 返回值和参数都是void* 类型
参4:参3的参数。没有的话,传NULL
返回值:成功:0 失败:errno

3.void pthread_exit(void* retval); 退出当前线程。

	retval:退出值。 无退出值时,NULL

该函数与进程退出函数exit()类似,目的是退出线程。
将其与其它函数进行对比:

exit(); 退出当前进程。
return: 返回到调用者那里去,结束当前函数。
pthread_exit(): 退出当前线程。

由于主线程可能先于子线程结束,所以子线程的可能在主线程结束前不能完全执行,可以用主线程sleep等待子线程结束来解决,而现在就可以使用pthread_exit来解决了。方法就是将return 0替换为pthread_exit,只退出当先线程,不会对其他线程造成影响。

4.int pthread_join(pthread_t thread, void** retval) 阻塞 回收线程。
thread: 待回收的线程id
retval:传出参数。 回收的那个线程的退出值。
线程异常借助,值为 -1。
返回值:成功:0 失败:errno

回收线程并获取其返回值的例子:

1.#include <stdio.h>  
2.#include <stdlib.h>  
3.#include <string.h>  
4.#include <unistd.h>  
5.#include <errno.h>  
6.#include <pthread.h>  
7.  //子线程返回此结构体
8.struct thrd {  
8.    int var;  
9.    char str[256];  
11.};  
10.  //错误处理
13.void sys_err(const char *str)  
14.{  
11.    perror(str);  
12.    exit(1);  
17.}  
13.  //线程执行函数
19.void *tfn(void *arg)  
20.{  
14.    struct thrd *tval;  
15.    //利用指针堆区创建,由于线程间共享堆区,所以主线程可以通过该指针访 
16.    //问结构体内容,反观创建在栈上,若子线程返回后结束,栈区连同该结构体
17.    //一起释放,主线程就无法访问。
18.    tval = malloc(sizeof(tval));  
19.    tval->var = 100;  
20.    strcpy(tval->str, "hello thread");  
21.    //子线程将此结构体地址转为void*返回
22.    return (void *)tval;  
28.}  
23.  
30.int main(int argc, char *argv[])  
31.{  
24.    pthread_t tid;  
25.    struct thrd *retval;  
26. 
27.    int ret = pthread_create(&tid, NULL, tfn, NULL);  
28.    if (ret != 0)  
29.        sys_err("pthread_create error");  
30.  
31.    //int pthread_join(pthread_t thread, void **retval);  
32.    ret = pthread_join(tid, (void **)&retval);  
33.    if (ret != 0)  
34.        sys_err("pthread_join error");  
35.  
36.    printf("child thread exit with var= %d, str= %s\n", retval->var, retval->str);  
37.      
38.    pthread_exit(NULL);  
39.  
49.}  

结果:
在这里插入图片描述
5.int pthread_cancel(pthread_t thread); 杀死一个线程。 (需要到达取消点(保存点))
取消点:相当于进入内核的一个契机,当子线程逻辑中有某些操作需要进入内核时,检查是否取消该线程。

参数:
thread: 待杀死的线程id
返回值:成功:0 失败:errno

如果,子线程没有到达取消点, 那么 pthread_cancel 无效。
我们可以在程序中,手动添加一个取消点。使用 pthread_testcancel();

成功被 pthread_cancel() 杀死的线程,返回(void*) -1. 可以使用pthead_join 回收。

借助cancel函数杀死线程例子:

1.#include <stdio.h>  
2.#include <stdlib.h>  
3.#include <string.h>  
4.#include <unistd.h>  
5.#include <errno.h>  
6.#include <pthread.h>  
7.  
8.  
9.void *tfn(void *arg){  
10.    while (1) {  
11.        printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());  
12.        sleep(1);  
13.    }  
14.  
15.    return NULL;  
16.}  
17.  
18.int main(int argc, char *argv[]){  
19.    pthread_t tid;  
20.  
21.    int ret = pthread_create(&tid, NULL, tfn, NULL);  
22.    if (ret != 0) {  
23.        fprintf(stderr, "pthread_create error:%s\n", strerror(ret));  
24.        exit(1);  
25.    }  
26.  
27.    printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());  
28.    //5秒后执行cancel函数,杀死线程
29.    sleep(5);  
30.  
31.    ret = pthread_cancel(tid);          // 以tid(线程id)终止线程  
32.    if (ret != 0) {  
33.        fprintf(stderr, "pthread_cancel error:%s\n", strerror(ret));  
34.        exit(1);  
35.    }  
36. 
37.
38.    pthread_exit((void *)0);  
39.}  

结果
在这里插入图片描述

注意一点,pthread_cancel工作的必要条件是进入内核,如果tfn真的奇葩到没有进入内核,则pthread_cancel不能杀死线程,此时需要手动设置取消点,就是pthread_testcancel()

6.int pthread_detach(pthread_t thread); 设置线程分离

线程分离,指线程执行完毕后无需其他线程使用join回收,而是会将自身回收。

thread: 待分离的线程id
返回值:成功:0 失败:errno

1.#include <stdio.h>  
2.#include <stdlib.h>  
3.#include <string.h>  
4.#include <unistd.h>  
5.#include <errno.h>  
6.#include <pthread.h>  
7.  
8.  
9.void *tfn(void *arg)  
10.{  
9.    printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());  
10.  
11.    return NULL;  
14.}  
12.  
16.int main(int argc, char *argv[])  
17.{  
13.    pthread_t tid;  
14.     //  线程创建
15.    int ret = pthread_create(&tid, NULL, tfn, NULL);  
16.    if (ret != 0) {  
17.        fprintf(stderr, "pthread_create error: %s\n", strerror(ret));  
18.        exit(1);  
19.    }  
20. 
21.     // 设置线程分离 线程终止,会自动清理pcb,无需回收  
22.    ret = pthread_detach(tid);            
23.    if (ret != 0) {  
24.        fprintf(stderr, "pthread_detach error: %s\n", strerror(ret));  
25.        exit(1);  
26.    }  
27     //等待子线程结束后,再使用join回收,测试结果
28.    sleep(1);  
29.     
30.    ret = pthread_join(tid, NULL);  //此时线程已经自动回收PCB,此函数会出错
31.    printf("join ret = %d\n", ret);  
32.    if (ret != 0) {  
33.        fprintf(stderr, "pthread_join error: %s\n", strerror(ret));  
34.        exit(1);  
35.    }  
36.  
37.    printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());  
38.  
39.    pthread_exit((void *)0);  
43.}  

结果,产生参数错误
在这里插入图片描述7.进程和线程控制原语对比
线程控制原语 -----------------进程控制原语
pthread_create() ----------------- fork();

pthread_self() -------------------- getpid();

pthread_exit() -------------------- exit(); / return

pthread_join() -------------------- wait()/waitpid()

pthread_cancel() ----------------- kill()

pthread_detach()----------------- 无

四.线程属性设置分离线程

pthread_create()的第二个参数,指定线程的属性,传入NULL表示默认属性,也可以传入线程属性结构体pthread_attr_t 来控制线程属性。

此次使用线程属性设置线程的线程分离

pthread_attr_t attr 创建一个线程属性结构体
pthread_attr_init(&attr); 初始化线程属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 设置线程属性为分离态
pthread_create(&tid, &attr, tfn, NULL); 传入修改后的线程属性 创建为分离态的新线程
pthread_attr_destroy(&attr); 销毁线程属性

五.线程使用注意事项

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年10款超好用的图纸加密软件推荐|企业常用图纸加密软件分享

在数字化时代&#xff0c;图纸作为企业的关键技术资产&#xff0c;承载着大量敏感信息&#xff0c;泄露这些图纸不仅可能导致重大经济损失&#xff0c;还可能危及企业的市场竞争力。因此&#xff0c;选择一款合适的图纸加密软件&#xff0c;对企业而言至关重要。为了帮助企业保…

【C#网络编程】基础概念2

文章目录 网络、数据包和协议网络数据包协议TCP、UDP 地址客户端和服务器套接字 网络、数据包和协议 计算机网络通过通信通道互连的机器组成&#xff0c;通常把这些机器称为主机和路由器&#xff0c;主机是是运行应用程序&#xff08;如 Web 浏览器&#xff09;的计算机。路由器…

市面上琳琅满目的网站开发公司,如何避免“踩坑”?

服务品质和售后服务是选择网站开发公司时的两大关键因素—— 因为这些方面将直接影响网站的质量、用户体验以及后期的维护效果&#xff0c;一家优秀的网站开发公司&#xff0c;其服务品质应体现在专业的技术水平、出色的项目管理能力以及对客户需求的精准理解和高效执行上。 …

今日最佳WAF雷池社区版,tengine问题解决办法

很多第一次使用雷池社区版的朋友会碰到tengine相关的问题 其实官方文档都有记录怎么排除&#xff0c;这里都单独把tengine的排查方法再说一下 请检查防火墙规则&#xff0c; tengine 容器状态和日志 如果站点报错如上&#xff0c;说明tengine容器可能出现问题&#xff0c;需…

Java | Leetcode Java题解之第475题供暖器

题目&#xff1a; 题解&#xff1a; class Solution {public int findRadius(int[] houses, int[] heaters) {Arrays.sort(houses);Arrays.sort(heaters);int ans 0;for (int i 0, j 0; i < houses.length; i) {int curDistance Math.abs(houses[i] - heaters[j]);whil…

【优选算法】(第四十篇)

目录 岛屿数量&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 岛屿的最⼤⾯积&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 岛屿数量&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;LeetCo…

双足机器人远程操作与动态运动同步研究

在当前的机器人技术中&#xff0c;双足机器人因其能够在复杂环境中灵活行动而备受关注。随着技术的进步&#xff0c;研究者们致力于开发能够与人类操作员实现高效同步的双足机器人&#xff0c;特别是在应对自然灾害或人为危险等紧急情况下的应用。 项目背景 尽管人工智能领域取…

在python中如何判断回文串(一)?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【原创】java+springboot+mysql智能农村管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

Voronoi treemap!这么好看的图形绘制原来这么简单...

更多详细的数据可视化教程&#xff0c;可订阅我们的店铺课程&#xff1a; 在上次推出树形图绘制教程之后&#xff0c;有小伙伴私信说有没有啥方法绘制如下所示的图表&#xff1a; 网友提供样例 (说实话&#xff0c;我第一眼看到之后就感觉R或者Python绘制此图会比较难&…

InstructGPT的四阶段:预训练、有监督微调、奖励建模、强化学习涉及到的公式解读

1. 预训练 1. 语言建模目标函数&#xff08;公式1&#xff09;&#xff1a; L 1 ( U ) ∑ i log ⁡ P ( u i ∣ u i − k , … , u i − 1 ; Θ ) L_1(\mathcal{U}) \sum_{i} \log P(u_i \mid u_{i-k}, \dots, u_{i-1}; \Theta) L1​(U)i∑​logP(ui​∣ui−k​,…,ui−1​;Θ…

智慧灌区信息化管理系统解决方案

一、方案背景 我国南方地区一些县级一般拥有5000多个大小水利设施&#xff0c; 尤其是灌区水利设施众多&#xff0c;这些灌区水利设施修建年代久&#xff0c;信息化程度低&#xff0c;但在保障农民生产、农田灌溉、抵抗自然灾害方面发挥着一定的作用&#xff0c;并能够最大限度…

go开发环境设置-安装与交叉编译(二)

1. 引言 Go语言&#xff0c;又称Golang&#xff0c;是Google开发的一门编程语言&#xff0c;以其高效、简洁和并发编程的优势受到广泛欢迎。作为一门静态类型、编译型语言&#xff0c;Go在构建网络服务器、微服务和命令行工具方面表现突出。 在开发过程中&#xff0c;开发者常…

科技云报到:大模型时代下,向量数据库的野望

科技云报到原创。 自ChatGPT爆火&#xff0c;国内头部平台型公司一拥而上&#xff0c;先后发布AGI或垂类LLM&#xff0c;但鲜有大模型基础设施在数据层面的进化&#xff0c;比如向量数据库。 在此之前&#xff0c;向量数据库经历了几年的沉寂期&#xff0c;现在似乎终于乘着Ch…

Yolov11与Yolov8在西红柿识别数据集上对比

Ultralytics 最新发布的 YOLOv11 相较于其上一代产品 YOLOv8&#xff0c;虽然没有发生革命性的变化&#xff0c;但仍有一些显著的改进&#xff08;值得注意的是&#xff0c;YOLOv9 和 YOLOv10 并非由 Ultralytics 开发&#xff09;。其中&#xff0c;最引人注目的变化包括&…

4.redis通用命令

文章目录 1.使用官网文档2.redis通用命令2.1set2.2get2.3.redis全局命令2.3.1 keys 2.4 exists2.5 del(delete)2.6 expire - (失效时间)2.7 ttl - 过期时间2.7.1 redis中key的过期策略2.7.2redis定时器的实现原理 2.8 type2.9 object 3.生产环境4.常用的数据结构4.1认识数据类型…

代码复现(四):DBINet

文章目录 datasets/AB2019BASDataset.pydatasets/ext_transforms.pynetwork/modules.pynetwork/DBINet.pynetwork/DBINet_Backbone.pyAB2019_train.py 代码链接&#xff1a;DBINet datasets/AB2019BASDataset.py 加载Australia Bushfire 2019 Burned Area Segmentation Datase…

【论文精读】RELIEF: Reinforcement Learning Empowered Graph Feature Prompt Tuning

Navigating the Digital World as Humans Do: UNIVERSAL VISUAL GROUNDING FOR GUI AGENTS 前言AbstractMotivationSolutionRELIEFIncorporating Feature Prompts as MDPAction SpaceState TransitionReward Function Policy Network ArchitectureDiscrete ActorContinuous Act…

【杂记】之语法学习第一课输入输出与数据类型与选择结构

首先学会新建源文件 1.打开DEV C 2.文件—>新建—>源代码 3.编写程序 4.编译并运行&#xff08;F11&#xff09; 第一个程序《Hello,World!》 题目描述 编写一个能够输出 Hello,World! 的程序。 提示&#xff1a; 使用英文标点符号&#xff1b;Hello,World! 逗号后…

8-基于双TMS320C6678 + XC7K420T的6U CPCI Express高速数据处理平台

1、板卡概述 板卡由我公司自主研发&#xff0c;基于6UCPCI架构&#xff0c;处理板包含双片TI DSP TMS320C6678芯片&#xff1b;一片Xilinx公司FPGA XC7K420T-1FFG1156 芯片&#xff1b;六个千兆网口&#xff08;FPGA两个&#xff0c;DSP四个&#xff09;&#xff1b;DSP与FPGA之…