线程知识点

news2024/11/17 2:35:41

一、线程

1.定义

线程:是一个进程并发执行多种任务的机制。

串行:多个任务有序执行,一个任务执行完毕后,再去执行下一个任务

并发:多个任务在单个CPU上运行,同一个时间片上只能运行一个任务,cpu不停在各个任务上切换

并行:多任务在多个cpu上运行,同一个时间片上可以执行多个任务

其中上下文:运行一个进程所需要的所有资源

上下文切换:切换进程时,cpu访问的资源需要替换原先的资源,进程的上下文切换是个耗时操作,所以引入线程。

因为线程属于同一进程下,共享其附属进程的所有资源。

2.进程和线程的区别

1.进程时资源分配的最小单位,线程是任务运行的最小单位

2.进程和进程之间相互独立,内核空间共享。进程之间数据通信需要引进IPC通信机制

3.线程与线程之间共享其附属进程的所有资源,所以线程之间通信不需要通信机制,但是需要注意同步互斥

4.多线程的效率比多进程高,多进程的稳定性比多线程高,多进程的资源量比多线程高

二、线程的创建  pthread_creat

gcc时需要加-pthread

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=NULL
{
    while (1)
    {
        printf("副线程\n");
        sleep(1);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, NULL) != 0)
    {
        // 第一个参数:线程成功创建后的tid号
        // 第二个参数:线程属性,一般填NULL,代表默认属性
        // 第三个参数:回调函数,void *(callback)(void *) 函数指针,指向返回值void*类型,参数列表式void*类型的函数
        // 第四个参数:传递给回调函数的参数
        fprintf(stderr, "创建线程失败");
    }
    while (1)
    {
        printf("主线程\n");
        sleep(1);
    }
    return 0;
}

 

pthread_creat传参

i.主线程向子线程传参

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=NULL
{
    while (1)
    {
        printf("副线程 a=%d,&a=%p\n", *(int *)arg, arg);
        sleep(1);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    int a = 10;
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, (void *)&a) != 0)
    {
        fprintf(stderr, "创建线程失败");
    }
    while (1)
    {
        printf("主线程   a=%d,&a=%p\n", a, &a);
        sleep(1);
    }
    return 0;
}

ii.子线程向主线程传参

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=&pa   &pa本身是int **类型
{
    int a = 10;
    *(int **)arg = &a; // 二级指针int**类型,解引用后,访问的是int**类型
    // 如果不强转,void*类型,就不知道要访问多少个字节
    while (1)
    {
        printf("副线程 a=%d,&a=%p\n", a, &a);
        sleep(1);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    int *pa = NULL;
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, (void *)&pa) != 0) // 要修改pa的值就要把pa的地址传过去
    {
        fprintf(stderr, "创建线程失败");
    }
    while (1)
    {
        if (pa != NULL)
        {
            printf("主线程   a=%d,&a=%p\n", *pa, pa);
            sleep(1);
        }
    }
    return 0;
}

三、线程的退出与回收 pthread_exit和pthread_join

i.不接收退出状态值

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=NULL
{
    int i = 0;
    while (i < 3)
    {
        printf("分支线程\n");
        sleep(1);
        i++;
    }
    printf("分支线程准备退出\n");
    pthread_exit(NULL); // 用于退出线程,不想传递退出状态值就填NULL
    return NULL;
}

int main(int argc, char const *argv[])
{
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, NULL) != 0)
    {
        fprintf(stderr, "创建线程失败");
    }
    pthread_join(tid, NULL);//阻塞等待分支进程结束
    // 第一个参数:分支线程的tid号
    // 第二个参数:null为不接收线程退出的状态值
    // 不为null则将pthread_exit传递的退出状态复制到该二级指针指向的一级指针中。
    printf("主线程准备退出\n");
    return 0;
}

ii.接收退出的状态值 

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=NULL
{
    int i = 0;
    while (i < 3)
    {
        printf("分支线程\n");
        sleep(1);
        i++;
    }
    printf("分支线程准备退出\n");
    static int a = 10; // 若不加static,则分支进程结束了之后,a也将不存在,加static来延长生命周期
    pthread_exit(&a);
    return NULL;
}

int main(int argc, char const *argv[])
{
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, NULL) != 0)
    {
        fprintf(stderr, "创建线程失败");
    }
    void *ptr = NULL;
    pthread_join(tid, &ptr);
    printf("%d\n", *(int *)ptr);
    printf("主线程准备退出\n");
    return 0;
}

练习:分别用两个线程来拷贝一张图片的前半部分和后半部分

#include <head.h>

// 拷贝前半部分
void *callback1(void *arg)
{
    // 以读的方式打开文件
    int fd_r = open("./1.png", O_RDONLY);
    if (fd_r < 0)
    {
        perror("open");
        return NULL;
    }
    // 以写的方式打开文件
    int fd_w = open("./copy.png", O_WRONLY);
    if (fd_w < 0)
    {
        perror("open");
        return NULL;
    }
    off_t size = lseek(fd_r, 0, SEEK_END); // 通过文件的偏移量来计算文件的大小
    // lseek的返回值为距离文件开头的偏移量

    // 修改文件偏移量到文件开头位置
    lseek(fd_r, 0, SEEK_SET);
    lseek(fd_w, 0, SEEK_SET);

    char c = 0;
    for (int i = 0; i < size / 2; i++)
    {
        read(fd_r, &c, 1);
        write(fd_w, &c, 1);
    }
    printf("前半部分拷贝完\n");
    // 关闭文件
    close(fd_r);
    close(fd_w);

    pthread_exit(NULL);
}

// 拷贝后半部分
void *callback2(void *arg)
{
    // 以读的方式打开文件
    int fd_r = open("./1.png", O_RDONLY);
    if (fd_r < 0)
    {
        perror("open");
        return NULL;
    }
    // 以写的方式打开文件
    int fd_w = open("./copy.png", O_WRONLY);
    if (fd_w < 0)
    {
        perror("open");
        return NULL;
    }
    off_t size = lseek(fd_r, 0, SEEK_END); // 通过文件的偏移量来计算文件的大小
    // lseek的返回值为距离文件开头的偏移量

    // 修改文件偏移量到文件开头位置
    lseek(fd_r, size / 2, SEEK_SET);
    lseek(fd_w, size / 2, SEEK_SET);

    char c = 0;
    for (int i = size / 2; i < size; i++)
    {
        read(fd_r, &c, 1);
        write(fd_w, &c, 1);
    }
    printf("后半部分拷贝完\n");
    // 关闭文件
    close(fd_r);
    close(fd_w);

    pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
    // 两个线程在拷贝前,确保文件存在且是清空状态
    int fd_w = open("./copy.png", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (fd_w < 0)
    {
        perror("open");
        return -1;
    }
    close(fd_w);

    // 创建两个线程
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, callback1, NULL) != 0)
    {
        fprintf(stderr, "分支线程1创建失败\n");
        return -1;
    }

    if (pthread_create(&tid2, NULL, callback2, NULL) != 0)
    {
        fprintf(stderr, "分支线程1创建失败\n");
        return -1;
    }

    // 阻塞等待分支线程退出
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    return 0;
}

四、分离线程 pthread_detach

分离线程,线程退出后资源由内核自动回收

当使用pthread_detach分离tid后,pthread_join就无法再回首tid线程的资源了且pthread_join不再阻塞

所以pthread_join和pthread_detach挑一个使用。

#include <head.h>

// 线程执行体,里面写副线程要执行的内容
void *callBack(void *arg) // void *arg=NULL
{
    printf("副线程\n");
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char const *argv[])
{
    // 创建一个分支线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, callBack, NULL) != 0)
    {
        fprintf(stderr, "创建线程失败");
    }
    pthread_detach(tid);
    printf("主线程\n");
    return 0;
}

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

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

相关文章

数据的均匀化分割算法(网格划分法、四叉树法(含C++代码))

数据的均匀化分割主要是指在分割过程中尽可能均匀地将数据点分布在各个子区域中&#xff0c;以保持数据分布的平衡和优化数据结构的性能。以下是几种可以实现数据均匀化分割的方法&#xff1a; 一. 网格划分法 1. 基本概念 虽然传统的网格划分法不是动态调整的&#xff0c;但通…

软件验收计划书-验收规程(Word原件)

编写软件验收计划是软件开发过程中的一个关键步骤&#xff0c;其重要性体现在以下几个方面&#xff1a; 明确验收标准&#xff1a;软件验收计划详细列出了验收的标准、测试方法、测试环境等&#xff0c;确保所有相关人员对验收的期望和要求有清晰的认识。这有助于避免在验收阶段…

Ansible---自动化运维工具

一、Ansible概述 1.1 Ansible简介 Ansible是一款自动化运维工具&#xff0c;通过ssh对目标主机进行配置、应用部署、任务执行、编排调度等操作。它简化了复杂的环境管理和自动化任务&#xff0c;提高了工作效率和一致性&#xff0c;同时&#xff0c;Ansible的剧本(playbooks)…

centos7.9升级4.19内核

centos默认的内核版本是3.10 通过命令 uname -a 输出系统的详细信息 在部署k8s集群时使用默认的3.10版本的内核&#xff0c;容易出各种奇奇怪怪的问题、可以理解为docker和k8s与该内核版本不兼容&#xff0c;所以在部署k8s集群时&#xff0c;务必要升级内核&#xff0c;这里…

【论文笔记 | 异步联邦】FedSA

FedSA&#xff1a;一种处理 non-IID 数据 的 过时感知 异步联邦算法 1. 论文信息 FedSA&#xff1a;A staleness-aware asynchronous Federated Learning algorithm with non-IID data&#xff0c;Future Generation Computer Systems&#xff0c;2021.7&#xff0c;ccfc 是…

即插即用篇 | YOLOv8引入局部自注意力 HaloAttention | 为参数高效的视觉主干网络扩展局部自注意力

本改进已集成到 YOLOv8-Magic 框架。 我们提出了Axial Transformers,这是一个基于自注意力的自回归模型,用于图像和其他组织为高维张量的数据。现有的自回归模型要么因高维数据的计算资源需求过大而受到限制,要么为了减少资源需求而在分布表达性或实现的便捷性上做出妥协。相…

05-10 周五 FastBuild 容器启动引起超时问题定位与解决

05-10 周五 FastBuild 容器启动超时问题 时间版本修改人描述2024年5月11日16:45:33V0.1宋全恒新建文档2024年5月11日22:37:21V1.0宋全恒完成解决方案的撰写&#xff0c;包括问题分析&#xff0c;docker命令 简介 关于FastBuild的优化&#xff0c;已经撰写了多个博客&#xff0…

C#知识|无边框的WinForm窗体,如何拖动位置?

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 上一节时练习做了一个简单的登录窗体界面&#xff0c;为了美观设置成了无边框&#xff0c; 当运行起来&#xff0c;发现无边框的窗体无法用鼠标拖动位置&#xff0c; 本节记录通过添加代码实现无边框窗体实现移动&…

IDEA创建springboot项目时不能选择java 8或者java 11等等版本的问题,解决方案

文章目录 1. Project JDK 和 Java 的区别2. 没有 java 8 或 java 11 等版本2.1 方案一2.2 方案二2.3 方案三 1. Project JDK 和 Java 的区别 我们在利用 idea 创建 spring boot 项目时&#xff0c;会有以上两个选项&#xff0c;这两个选项有什么区别&#xff1f; 答&#xff…

二、jacoco代码覆盖率工具

jacoco代码覆盖率工具 一、jacoco介绍二、常见的java代码覆盖率工具三、为什么选择jacoco四、jacoco的特点五、Jacoco 支持的覆盖率指标六、那些暂未支持的覆盖率指标七、jacoco技术原理八、Jacoco 下载与配置九、jacoco主要文件十、jacoco使用流程 一、jacoco介绍 JaCoCo 是一…

【GESP】2023年12月图形化二级 -- 小杨报数

小杨报数 【题目描述】 小杨需要从 1 1 1到 N N N报数。在报数过程中&#xff0c;小杨希望跳过 M M M的倍数。例如&#xff0c;如果 N 5 N5 N5&#xff0c; M 2 M2 M2&#xff0c;那么小杨就需要依次报出 1 1 1&#xff0c; 3 3 3&#xff0c; 5 5 5。 默认小猫角色和白色背…

LED液晶显示屏(LCD/TFT)抗干扰太阳光模拟器

LED&液晶显示屏(LCD/TFT)抗干扰太阳光模拟器&#xff1a;解决驾驶员视线问题 在驾车过程中&#xff0c;太阳光的干扰是一个常见的问题。特别是在高速公路等需要高度集中注意力的情况下&#xff0c;太阳光的干扰会严重影响驾驶员的视线&#xff0c;增加驾驶风险。为了解决这…

eNSP中小型园区网络拓扑搭建(上)

→b站直通车&#xff0c;感谢大佬← →eNSP中小型园区网络拓扑搭建&#xff08;下&#xff09;← 不带配置命令的拓扑图已上传~ 项目背景&#xff1a; 某公司准备新建一张网络供企业办公使用。写字楼共3层&#xff0c;一层会客大厅、二层行政部及市场部、三层研发部。一层设…

容器监控与日志管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、Docker监控工具 二、容器日志工具docker logs 三、第三方日志工具 四、容器日志驱动 五、示例 5.1、查看容器中运行的进程的信息 5.2、查看…

TEINet: Towards an Efficient Architecture for Video Recognition 论文阅读

TEINet: Towards an Efficient Architecture for Video Recognition 论文阅读 Abstract1 Introduction2 Related Work3 Method3.1 Motion Enhanced Module3.2 Temporal Interaction Module3.3 TEINet 4 Experiments5 Conclusion阅读总结 文章信息; 原文链接&#xff1a;https:…

BUU-[极客大挑战 2019]Http

考察点 信息收集 http构造请求数据包 题目 解题步骤 参考文章&#xff1a;https://zhuanlan.zhihu.com/p/367051798 查看源代码 发现有一个a标签&#xff0c;但是οnclick"return false"就是点击后不会去跳转到Secret.php的页面 所以我就自己拼接url http://no…

工业机器人应用实践之玻璃涂胶(篇二)

工业机器人 接上篇文章&#xff0c;浅谈一下实践应用&#xff0c;具体以玻璃涂胶为例&#xff1a; 了解工业机器人在玻璃涂胶领域的应用认识工具坐标系的标定方法掌握计时指令的应用掌握人机交互指令的应用掌握等待类指令用法&#xff08;WaitDI、WaitUnitl 等&#xff09;认…

表面的相似,本质的不同

韩信与韩王信&#xff0c;两个韩信的结局都是被刘邦所杀&#xff0c;似乎结局类似。但是&#xff0c;略加分析&#xff0c;就会发现其中存在本质的区别。 韩信属于必杀。他的王位是要来的&#xff0c;有居功自傲的本意&#xff0c;功高震主而且毫不避讳。而且年轻&#xff0c;…

REFORMER: 更高效的TRANSFORMER模型

大型Transformer模型通常在许多任务上都能达到最先进的结果&#xff0c;但是训练这些模型的成本可能会非常高昂&#xff0c;特别是在处理长序列时。我们引入了两种技术来提高Transformer的效率。首先&#xff0c;我们用一种使用局部敏感哈希的点积注意力替换了原来的点积注意力…

Apache ECharts

Apache ECharts介绍&#xff1a; Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。 官网地址&#xff1a;https://echarts.apache.org/zh/index.html Apache ECh…