线程(Thread)

一、概念

线程:线程是一个轻量级的进程

 二、线程的创建

1、线程的空间

(1)进程的空间包括:系统数据段、数据段、文本段

(2) 线程位于进程空间内部

(3) 栈区独享、与进程共享文本段、数据段、堆区

2、线程与进程的关系

进程:进程是操作系统资源分配的最小单元(进程:文本段+数据段+系统数据段)

线程:线程是CPU任务调度的最小单元

        (1)每个线程独立拥有8M(默认)栈空间

        (2)其余的文本段、数据段、堆区都是与进程及进程内的其余线程共享的

三、线程的调度

(1)线程的调度等价于进程的调度(宏观并行,微观串行)

         线程之间宏观并行,微观串行;所以线程在执行的过程中,会出现以下情况:
                情况一:线程1先执行,线程二后执行
                情况二:线程2先执行,线程1后执行
                情况三:线程2执行一半后执行线程1,线程1执行一半后执行线程2,即二者交叉执行

(2)线程是CPU任务调度的最小单元

四、线程的消亡 

(1)与进程消亡保持一致,进程结束时不论线程处于什么状态,线程被强制结束

(2)僵尸线程:等到线程结束需要回收线程空间,否则会产生僵尸线程

五、多进程vs多线程

1、执行效率

多线程 > 多进程

线程 间任务的切换是在同一片进程空间内部完成任务切换,资源开销小

进程 间任务的切换需要映射到不同的物理地址空间,频繁切换资源开销大

2、多任务间通信的实现

多线程 > 多进程

多线程 拥有共享空间(多个线程位于一个进程内,共享该进程的数据区、文本区),通信更加方便

多进程 没有共享空间(进程间是独立的),需要更为复杂的方法实现多进程间通信

3、多任务通信机制的复杂程度

多线程 > 多进程

多线程 操作全局变量会引入资源竞争,需要加锁来解决

多进程 没有资源竞争

4、安全性

多进程 > 多线程

线程 异常崩溃导致进程崩溃,该进程中的其余线程异常结束

进程 异常结束,不会影响其余进程

六、线程相关的函数接口

pthread_create == fork 

pthread_exit == exit 

pthread_join == wait 

 1、pthread_creat

man 3 pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,                                                                               void *(*start_routine) (void *), void *arg);

功能:

        在调用函数的进程中创建一个线程

参数:

        thread:存放线程ID空间的首地址

        attr:线程的属性

        start_routine:线程函数的入口

                             void *(*start_routine) (void *)函数指针,返回值类型void*,参数void*,*start_routine:函数首地址(函数名本身就是函数首地址)

        arg:传入线程函数的参数(给start_routine函数传的参数)

返回值:

        成功返回0

        失败返回错误数字

#include <stdio.h>
#include "public.h"      //头文件中包含pthread_creat的头文件,但是编译时还需使用 -lpthread(链接头文件)//cc src/main.c -o ./build/a.out -I./include -lpthreadvoid *thread_fun(void *arg)
{printf("线程(TID:%#x)开始执行\n", (unsigned int)pthread_self());    //pthread_self获取线程IDreturn NULL;
}int main(int argc, const char **argv)
{pthread_t tid1;pthread_t tid2;pthread_t tid3;int ret = 0;ret = pthread_create(&tid1, NULL, thread_fun, NULL);if (ret != 0){ERR_MSG("fail to pthread_create");return -1;}ret = pthread_create(&tid2, NULL, thread_fun, NULL);if (ret != 0){ERR_MSG("fail to pthread_create");return -1;}ret = pthread_create(&tid3, NULL, thread_fun, NULL);if (ret != 0){ERR_MSG("fail to pthread_create");return -1;}while (1){}return 0;
}

 2、pthread_exit

man 3 pthread_exit

void pthread_exit(void *retval);

功能:

        线程退出

参数:

        retval:线程退出的值

返回值:

        缺省

3、pthread_join

man 3 pthread_join

int pthread_join(pthread_t thread, void **retval);

功能:

        回收线程空间

参数:

        thread:要回收的线程的ID

        retval:存放线程结束状态指针空间的首地址

返回值:

        成功返回0

        失败返回错误码

注意:

        1.pthread_join具有阻塞功能,线程不结束,一直等到线程结束,回收到线程空间再继续向下执 行

        2.pthread_join具有同步功能

#include <stdio.h>
#include "public.h"#if 0
int main(int argc,const char** argv)
{pthread_t tid1;pthread_t tid2;pthread_t tid3;pthread_create(&tid1, NULL, thread1, NULL);pthread_create(&tid2, NULL, thread2, NULL);pthread_create(&tid3, NULL, thread3, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);	return 0;
}#endif#if 0
void *thread1(void *arg)
{printf("线程1(TID:%#lx)正在执行\n", pthread_self());return NULL;
}void *thread2(void *arg)
{printf("线程2(TID:%#lx)正在执行\n", pthread_self());return NULL;
}void *thread3(void *arg)
{printf("线程3(TID:%#lx)正在执行\n", pthread_self());return NULL;
}int main(int argc, const char **argv)
{pthread_t tid[3];int i = 0;int a[3] = {1, 2, 3};void *(*pfun[3])(void *) = {thread1, thread2, thread3};                 //函数指针数组for (i = 0; i < 3; i++){pthread_create(&tid[i], NULL,pfun[i],NULL);}for (i = 0; i < 3; i++){pthread_join(tid[i], NULL);}#endif#if 1
void *thread(void* arg)
{int* pnum = arg;printf("线程%d(TID:%#lx)正在执行\n", *pnum, pthread_self());return NULL;
}int main(int argc, const char **argv)
{pthread_t tid[3];int i = 0;int a[3] = {1, 2, 3};for (i = 0; i < 3; i++){//pthread_create(&tid[i], NULL,thread,&i);                   //error 所有线程共享同一个 i 的地址,因此当线程函数 thread 访问 &i 时,获取的值可能是循环结束后 i 的最终值(即 3),而不是创建线程时的值。这会导致所有线程可能接收到相同的值3,而不是预期的 0、1、2pthread_create(&tid[i], NULL,thread,&a[i]);                //right 数组 a 的值是固定的({1, 2, 3}),每个线程会接收到数组 a 中对应索引的值。由于每个线程接收的是数组 a 中不同元素的地址,线程函数 thread 可以正确地访问到 1、2、3 这些值}for (i = 0; i < 3; i++){pthread_join(tid[i], NULL);}
#endifreturn 0;
}

七、线程的分离属性

 1、概念

线程结束后,操作系统自动回收线程空间,无需调用pthread_join来回收线程空间

 2、函数接口

man 3 pthread_attr_setdetachstate

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

功能:

        将线程属性中加入分离属性

        在这种状态下,线程终止时会自动释放其资源,无需其他线程调用 pthread_join()

参数:

        attr:线程属性空间首地址

        detachstate: PTHREAD_CREATE_DETACHED   分离属性         PTHREAD_CREATE_JOINABLE   加入属性

返回值:

        成功返回0

        失败返回错误码

      pthread_attr_setdetachstate需要用到的辅助函数

        

        //对attr进行初始化

       int pthread_attr_init(pthread_attr_t *attr);  
       //销毁attr

        int pthread_attr_destroy(pthread_attr_t *attr);

#include <stdio.h>
#include "public.h"#if 1
int is_exit = 0;void* thread1(void* arg)
{int cnt = 0 ;while(!is_exit){if(cnt == 2){printf("采集线程正在执行!\n");cnt = 0;}cnt++;usleep(500000);}return NULL;
}
void* thread2(void* arg)
{int cnt = 0 ;while(!is_exit){if(cnt == 4){printf("显示线程正在执行!\n");cnt = 0;}cnt++;usleep(500000);}return NULL;
}
void* thread3(void* arg)
{int cnt = 0 ;while(!is_exit){if(cnt == 10){printf("存储线程正在执行!\n");cnt = 0;}cnt++;usleep(500000); }return NULL;
}
void* thread4(void* arg)
{int cnt = 0 ;while(!is_exit){if(cnt == 20){printf("日志线程正在执行!\n");cnt = 0;}cnt++;usleep(500000);         //同样是睡眠10秒但这样的操作让单位时间缩短了,避免了线程正在睡眠时线程结束的情况//sleep(10)               }return NULL;
}
int main(int argc,const char** argv)
{int i = 0;pthread_t tid[4];pthread_attr_t attr;void*(*pfun[4])(void*) = {thread1,thread2,thread3,thread4};char tmpbuff[1024] = {0};pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);for(i = 0;i < 4;i++){pthread_create(&tid[i],&attr, pfun[i], NULL);}pthread_attr_destroy(&attr);while(1){	gets(tmpbuff);if(0 == strcmp(tmpbuff,".quit")){is_exit = 1;break;}}sleep(1);                                 //进程睡眠1秒,确保线程完全执行过    return 0;
}#endif

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

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

相关文章

【含文档+PPT+源码】基于微信小程序的校园志愿者管理系统的设计与实现

项目介绍 本课程演示的是一款 基于微信小程序的校园志愿者管理系统的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本…

yolov8,yolo11,yolo12 服务器训练到部署全流程 笔记

正在进行中&#xff0c;随时更新 一. Anaconda配置 1.安装anaconda (1)下载.sh文件 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror (2)scp到服务器后&#xff0c;运行安装包 bash Anaconda3-2020.07-Linux-x86_64.sh (3)安装anacond…

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南20250302

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南 引言 在 Linux 服务器操作系统领域&#xff0c;CentOS 和 Ubuntu 是广泛采用的发行版。它们在命令集、默认工具链及生态系统方面各有特点。本文深入剖析 CentOS 与 Ubuntu 在常用命令层面的异同&#xff0c;并结合实践案例…

Java并发编程之可见性、原子性和有序性

引言 CPU缓存与内存产生的一致性问题(可见性) CPU时间片切换产生的原子性问题 CPU指令编译优化产生的有序性问题 并发编程问题的根源 CPU、内存、I/O设备三者速度差异一直是 核心矛盾 三者速度差异可形象描述为:天上一天(CPU),地上一年(内存),地下十年(I/O) 根据木桶理…

【Maui】系统找不到指定的文件Xamarin.Android.Aapt2.targets

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 And…

【STM32+cubemx】0024 HAL库开发:IAP(在应用编程)的实现

IAP在应用编程&#xff08;In-Application Programming&#xff09;&#xff0c;指的是MCU在运行应用程序时&#xff0c;能接收新的烧写文件&#xff0c;并更新到自身的程序存储器中。即可以在应用程序运行时在线升级。 本节我们通过一个简单的例子&#xff0c;来实现STM32的IA…

【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f4da;欢迎订阅专栏…

【Linux第一弹】Linux基础指令(上)

目录 1.ls指令 1.1 ls使用实例 2.pwd指令 3.cd指令 3.1 cd使用实例 4.touch指令 4.1touch使用实例 5.mkdir指令 5.1mkdir使用实例 6.rmdir指令和rm指令 6.1 rmdir指令使用实例->: 6.2 rm指令使用实例 7.man指令 8.cp指令 8.1 cp 使用实例 9.mv指令 9.1mv使用…

智能合约安全 | 合约无效化攻击

目录&#xff1a; 智能合约安全 合约无效化攻击 合约自毁函数 selfdestruct 攻击实现 漏洞防御 总结 智能合约安全 合约无效化攻击 合约无效化攻击类同于web安全中的逻辑漏洞中的一种 我们这里拿一个典型的例子来讲解 有这样一份智能合约, 每个人可以向其中发送1 eth 第七个…

蓝桥 发现环

0发现环 - 蓝桥云课 找到环 不过在最近一次维护网络时&#xff0c;管理员误操作使得某两台电脑之间增加了一条数据链接&#xff0c;于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径&#xff0c;使得这些电脑上的数据传输出现了BUG。 为了恢复正常传输&am…

weaviate 安装与测试

weaviate 安装 前提条件&#xff1a;docker安装完成 步骤&#xff1a; 开启docker 在终端运行命令 docker run -p 8080:8080 -p 50051:50051 cr.weaviate.io/semitechnologies/weaviate:1.29.0 weaviate 测试 python-client安装代码测试 import weaviate client weaviat…

SpringBoot原理-02.自动配置-概述

一.自动配置 所谓自动配置&#xff0c;就是Spring容器启动后&#xff0c;一些配置类、bean对象就自动存入了IOC容器当中&#xff0c;而不需要我们手动声明&#xff0c;直接从IOC容器中引入即可。省去了繁琐的配置操作。 我们可以首先将spring项目启动起来&#xff0c;里面有一…

内容中台与企业内容管理架构解析

内容中台技术架构解析 内容中台的技术架构以数据资产化和服务API化为核心&#xff0c;通过解耦内容生产与消费环节构建数字化基础设施。其架构通常包含统一内容池、智能处理引擎和开放接口层三大模块&#xff1a;统一内容池通过标准化元数据模型对多源异构内容进行结构化存储&…

DeepSeek开源周Day2:DeepEP - 专为 MoE 模型设计的超高效 GPU 通信库

项目地址&#xff1a;https://github.com/deepseek-ai/DeepEP 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (2/5)&#xff01; ​ ​ 引言 在大模型训练中&#xff0c;混合专家模型&#xff08;Mixture-of-Experts, MoE&#xff09;因其动…

密码学(哈希函数)

4.1 Hash函数与数据完整性 数据完整性&#xff1a; 检测传输消息&#xff08;加密或未加密&#xff09;的修改。 密码学Hash函数&#xff1a; 构建某些数据的简短“指纹”&#xff1b;如果数据被篡改&#xff0c;则该指纹&#xff08;以高概率&#xff09;不再有效。Hash函数…

网络流算法: Edmonds-Karp算法

图论相关帖子 基本概念图的表示: 邻接矩阵和邻接表图的遍历: 深度优先与广度优先拓扑排序图的最短路径:Dijkstra算法和Bellman-Ford算法最小生成树二分图多源最短路径强连通分量欧拉回路和汉密尔顿回路网络流算法: Edmonds-Karp算法网络流算法: Dinic算法 环境要求 本文所用…

R语言+AI提示词:贝叶斯广义线性混合效应模型GLMM生物学Meta分析

全文链接&#xff1a;https://tecdat.cn/?p40797 本文旨在帮助0基础或只有简单编程基础的研究学者&#xff0c;通过 AI 的提示词工程&#xff0c;使用 R 语言完成元分析&#xff0c;包括数据处理、模型构建、评估以及结果解读等步骤&#xff08;点击文末“阅读原文”获取完整代…

深度学习简介

目录 一、剖析&#xff0c;什么是深度学习&#xff1f;二、深度学习人工神经网络、机器学习、人工智能关系三、深度学习的发展3.1 从感知机到人工神经网络1. 早期发展2. 陷入低谷3. 短暂复兴4. 再次受挫5. 深度突破 3.2 深度学习时代1. 语音领域突破2. 大规模图像数据库3. Alex…

进行性核上性麻痹患者的生活护理指南

进行性核上性麻痹是一种神经系统退行性疾病&#xff0c;合理的生活护理能有效改善症状&#xff0c;提高生活质量。 居家环境要安全。移除地面杂物&#xff0c;铺设防滑垫&#xff0c;安装扶手&#xff0c;降低跌倒风险。在浴室、厨房等湿滑区域要特别加强防护措施。建议在床边、…

【数据结构】链表与顺序表的比较

链表和顺序表是两种常见的数据结构&#xff0c;各有优缺点&#xff0c;适用于不同的场景。 ### 顺序表&#xff08;数组&#xff09; 顺序表在内存中连续存储元素&#xff0c;支持随机访问。 **优点&#xff1a;** 1. **随机访问**&#xff1a;通过索引直接访问元素&#xf…