线程知识点

一、线程

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

漫谈AI时代的手机

以chatGPT 为代表的大语言的横空出世使人们感受到AI 时代的到来&#xff0c;大语言模型技术的最大特点是机器开始”懂人话“&#xff0c;”说人话“了。如同任何一个革命性工具的出现一样&#xff0c;它必将改变人类生活和工作。 在这里。我谈谈AI时代的手机。 语音通信的历史…

如何将Hyper-V转VMware?反之亦可

为何要在Hyper-V和VMware之间进行转换呢&#xff1f; 尽管VMware和Microsoft Hyper-V都是当前流行的一类虚拟机监控程序&#xff0c;但它们并不相互兼容。VMware产品使用VMDK格式创建虚拟磁盘&#xff0c;而Hyper-V则使用VHD或VHDX格式创建虚拟磁盘。 有时您可能需要进行这种转…

找不到msvcp120dll,无法继续执行代码的多种解决方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要采取一些措施来修复丢失的msvcp120.dll文件。本文将介绍6种常见的解决方法&…

cubic 相比 bbr 并非很糟糕

迷信 bbr 的人是被它的大吞吐所迷惑&#xff0c;我也不想再解释&#xff0c;但我得反过来说一下 cubic 并非那么糟。 想搞大吞吐的&#xff0c;看看我这个 pixie 算法&#xff1a;https://github.com/marywangran/pixie&#xff0c;就着它的思路改就是了。 cubic 属于 aimd-ba…

c++ STL 之栈—— stack 详解

vector 是 stl 的一个关联容器,名叫“栈”&#xff0c;何为“栈”&#xff1f;其实就是一个数组&#xff0c;但有了数组何必还需栈&#xff0c;这是一个高深的问题。 一、简介 1. 定义 栈&#xff0c;是一个柔性数组&#xff08;可变长数组&#xff09;&#xff0c;可以变大变小…

【qt】纯代码界面设计

界面设计目录 一.界面设计的三种方式1.使用界面设计器2.纯代码界面设计3.混合界面设计 二.纯代码进行界面设计1.代码界面设计的总思路2.创建项目3.设计草图4.添加组件指针5.初始化组件指针6.添加组件到窗口①水平布局②垂直布局③细节点 7.定义槽函数8.初始化信号槽9.实现槽函数…

最新!TOP200高校!5月ESI排名,公布!

【SciencePub学术】5月9日&#xff0c;ESI数据库更新了2024年5月最新ESI数据。据统计&#xff0c;全球共有9019家科研机构上榜&#xff0c;其中有449所中国内地高校。 ESI&#xff08;基本科学指标数据库&#xff09;是目前世界范围内普遍用以评价高校、学术机构、国家或地区国…

JavaScript 动态网页实例 —— 事件处理应用

前言 事件处理的应用很广泛。在事件处理的应用中,鼠标事件的应用是最常用到的。本章给出几个鼠标事件处理应用的示例,包括:页面预览、图像切换、点亮文本、鼠标跟随、鼠标感应和禁用鼠标按键。在这些示例中,有的可以直接拿来应用,有的则只提供了一种应用的方法,稍加拓展,…

深入解析RedisSearch:全文搜索的新维度

码到三十五 &#xff1a; 个人主页 在当今的数据时代&#xff0c;信息的检索与快速定位变得尤为关键。Redis&#xff0c;作为一个高性能的内存数据库&#xff0c;已经在缓存和消息系统中占据了重要地位。然而&#xff0c;Redis并不直接支持复杂的搜索功能。为了填补这一空白&am…

QT7_视频知识点笔记_3_自定义控件,事件处理器⭐,定时器,QPainter,绘图设备,不规则窗口

第三天&#xff1a; 自定义控件&#xff0c;事件处理器⭐&#xff0c;定时器&#xff0c;QPainter,绘图设备&#xff0c;不规则窗口实现 1.自定义控件&#xff1a; 创建新的QT控件类&#xff0c;然后再需要使用的地方--》提升为 来使用如何使用基础控件的信号和槽函数&…

Flutter-Statewidget 创建State过程State<XXXX> createState() => _XXXXState()的解释

文章目录 创建widget 的状态对象示例代码解析 完整的代码示例总结 创建widget 的状态对象 今天有个同学问了我下State createState() > _XXXXState()时什么意思。这个代码在flutter开发中一直看到&#xff0c;很多人都不关心这个&#xff0c;直接当模板使用。今天来介绍下这…

Python中tkinter编程入门3

在使用tkinter创建了窗口之后&#xff0c;可以将一些控件“放置”到窗口中。这些控件包括标签、按键以及输入框等。 1 在窗口中“放置”标签 在窗口中“放置”标签主要有两个步骤&#xff0c;一是创建标签控件&#xff0c;二是将创建好的标签“放置”到窗口上。 1.1 创建标签…

Maven- Profile详解

前言 Profile能让你为一个特殊的环境自定义一个特殊的构建&#xff1b;profile使得不同环境间构建的可移植性成为可能。 <project><profiles><profile><build><defaultGoal>...</defaultGoal><finalName>...</finalName><…

通过自建镜像方式搭建RabbitMQ集群

通过自建镜像方式搭建RabbitMQ集群 1. 应用准备1.1 应用目录结构1.2 配置文件1.2.1 .erlang.cookie1.2.2 hosts1.2.3 rabbitmq.conf1.2.4 rabbitmq-env.conf 2. 编写DockerFile2.1 将所有本地文件拷贝到工作目录2.2 拷贝文件到源目录&增加执行权限2.3 安装Erlang & rab…

WAAP全站防护理念,发现和保护敏感数据

数据是现代企业的新石油&#xff1a;正确使用它可以促进公司的发展并帮助企业在竞争中领先。就像石油一样&#xff0c;原始数据和未被发现的数据是毫无用处的&#xff0c;企业将无法从中受益&#xff1b;在最坏的情况下&#xff0c;它可能会导致安全事件。这也是企业投资敏感数…

Python | Leetcode Python题解之第75题颜色分类

题目&#xff1a; 题解&#xff1a; class Solution:def sortColors(self, nums: List[int]) -> None:n len(nums)p0, p2 0, n - 1i 0while i < p2:while i < p2 and nums[i] 2:nums[i], nums[p2] nums[p2], nums[i]p2 - 1if nums[i] 0:nums[i], nums[p0] num…

R语言数据探索与分析-碳排放分析预测

# 安装和加载需要的包 install.packages("readxl") install.packages("forecast") install.packages("ggplot2") library(readxl) library(forecast) library(ggplot2)# 数据加载和预处理 data <- read_excel("全年数据.xlsx") co…

全新神经网络架构KAN——本文用于学习与探索

论文地址&#xff1a;https://arxiv.org/pdf/2404.19756 Github&#xff1a;GitHub - KindXiaoming/pykan: Kolmogorov Arnold Networks 文档说明&#xff1a;Welcome to Kolmogorov Arnold Network (KAN) documentation! — Kolmogorov Arnold Network documentation 本文仅…

A计算机上的程序与B计算机上部署的vmware上的虚拟机的程序通讯 如何配置?

环境&#xff1a; 在A计算机上运行着Debian11.3 Linux操作系统&#xff1b;在B计算机上运行着Windows10操作系统&#xff0c;并且安装了VMware软件&#xff0c;然后在VMware上创建了虚拟机C并安装了CentOS 6操作系统 需求&#xff1a; 现在A计算机上的程序需要同虚拟机C上的软…

【RAG 论文】Contriever:对比学习来无监督训练文本嵌入模型

论文&#xff1a;Unsupervised Dense Information Retrieval with Contrastive Learning ⭐⭐⭐⭐⭐ Facebook Research, arXiv:2112.09118 Code&#xff1a;github.com/facebookresearch/contriever 一、论文速读 本文使用对比学习的方法来对文本检索模型做无监督学习训练&am…