学习记录——day24 多线程编程

news2025/1/12 12:25:50

目录

多线程局部概念

线程支持函数(多线程编程)

pthread_create:创建线程

 pthread -self:线程号获取

pthread_exit:线程退出函数

pthread_jion:线程资源回收

pthred_detath:线程分离态

pthread_cancel:线程取消函数

pthread_sercancelstate:设置取消属性

多线程允许使用同一个线程体函数

作业


多线程局部概念

        1)线程:也称为轻量版的进程(LWP),是更小的任务执行单元,是进程的一个执行路径

        2)线程是任务器调度的最小单位

        3)个进程中可以包含多个线程,多个线程共享进程的资源

        4)线程几乎不占用资源,只是占用了很少的用于程序状态的资源(大概有8k左右)

        5)由于多个线程共同使用进程的资源,导致,线程在操作上容易出现不安全的状态

        6)线程操作开销较小、任务切换效率较高

        7)一个进程中,至少要包含一个线程(主线程)

        8)在有任务执行漫长的IO等待过程中,可以同时执行其他任务

        9)linux中不直接支持线程相关的支持库,需要引入第三方库,线程支持库

                sudo apt-get install manpages-posix manpages-posix-dev

                如果程序中使用的线程支持库中的函数,编译程序时,需要加上-pthread 选项

线程支持函数(多线程编程)

pthread_create:创建线程

       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
       功能:在当前进程中,创建一个分支线程
       参数1:用于接收创建好的线程ID
       参数2:线程的属性,一般填NULL表示使用系统默认的属性创建线程
       参数3:线程体函数,需要传递一个函数,参数为void*,返回值为void*
       参数4:参数3的参数
       返回值:成功创建返回0,失败返回一个错误码,注意,不是内核提供的错误码       
 

#include <myhead.h>

struct Buf
{
    int num;
    double key;
};

void *task(void *arg)
{
    int num = (*((struct Buf*)arg)).num;
    double key = ((struct Buf*)arg)->key;
    while (1)
    {
        printf("分支线程  num = %d,key = %.2lf\n",num,key);
        sleep(1);
    }
}

int main(int argc, char const *argv[])
{
    int num = 2024;
    double key = 1024;

    struct Buf buf = {num,key};

    pthread_t tid = 1;

    if (pthread_create(&tid, NULL, task, &buf) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx\n",tid);

    getchar();
    while (1);

    return 0;
}

 pthread -self:线程号获取

       #include <pthread.h>

       pthread_t pthread_self(void);
    功能:获取当前线程的线程号
    参数:无
    返回值:当前线程的线程号

pthread_exit:线程退出函数

       #include <pthread.h>

       void pthread_exit(void *retval);
    功能:退出当前的线程
    参数:线程退出时的状态,一般填NULL
    返回值:无

#include <myhead.h>

void *task(void *arg)
{
    printf("子线程线程号 = %#lx\n", pthread_self());
    
    //exit(EXIT_SUCCESS);  //再线程中进程退出  主线程也会结束
    pthread_exit(NULL);  //线程退出 不影响主线程
}

int main(int argc, char const *argv[])
{
    //定义变量存储线程号
    pthread_t tid = 1;

    //创建线程
    if (pthread_create(&tid, NULL, task, NULL) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx 线程号 = %#lx\n", tid, pthread_self());

    //阻塞函数  主线程结束进程结束,分支线程也终止
    getchar();

    return 0;
}

pthread_jion:线程资源回收

       #include <pthread.h>

       int pthread_join(pthread_t thread, void **retval);
    功能:阻塞等待给定线程的退出,并回收该线程的资源
    参数1:要回收的线程号
    参数2:接收线程退出时的状态
    返回值:成功返回0,失败返回错误码

#include <myhead.h>

void *task(void *arg)
{
    printf("子线程 线程号 = %#lx\n", pthread_self());
    
    sleep(3);
    //exit(EXIT_SUCCESS);  //再线程中进程退出  主线程也会结束
    pthread_exit(NULL);  //线程退出 不影响主线程
}

int main(int argc, char const *argv[])
{
    //定义变量存储线程号
    pthread_t tid = 1;

    //创建线程
    if (pthread_create(&tid, NULL, task, NULL) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx 线程号 = %#lx\n", tid, pthread_self());

    //阻塞回收分支线程的资源
    if(pthread_join(tid,NULL) == 0)
    {
        printf("成功回收%#lx的资源\n",tid);
    }

    //阻塞函数  主线程结束进程结束,分支线程也终止
    getchar();

    return 0;
}

pthred_detath:线程分离态

       #include <pthread.h>

       int pthread_detach(pthread_t thread);
    功能:将线程设置成分离态,设置了分离态的线程,退出后,由系统回收其资源
    参数:要被分离的线程id号
    返回值:成功返回0,失败返回错误码

#include <myhead.h>

void *task(void *arg)
{
    printf("子线程 线程号 = %#lx\n", pthread_self());
    
    sleep(3);
    //exit(EXIT_SUCCESS);  //再线程中进程退出  主线程也会结束
    pthread_exit(NULL);  //线程退出 不影响主线程
}

int main(int argc, char const *argv[])
{
    //定义变量存储线程号
    pthread_t tid = 1;

    //创建线程
    if (pthread_create(&tid, NULL, task, NULL) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx 线程号 = %#lx\n", tid, pthread_self());

    // //阻塞回收分支线程的资源
    // if(pthread_join(tid,NULL) == 0)
    // {
    //     printf("成功回收%#lx的资源\n",tid);
    // }

    //将线程设置成分离态
    pthread_detach(tid);
    printf("线程已退出\n");

    //阻塞函数  主线程结束进程结束,分支线程也终止
    getchar();

    return 0;
}

pthread_cancel:线程取消函数

#include <myhead.h>

void *task(void *arg)
{
    int n =0;
    while (1)
    {
        printf("子线程 线程号 = %#lx\n", pthread_self());
        n++;
        sleep(1);
        if (n == 10)
        {
            break;
        }
        
    }
    
    
    
    //exit(EXIT_SUCCESS);  //再线程中进程退出  主线程也会结束
    pthread_exit(NULL);  //线程退出 不影响主线程
}

int main(int argc, char const *argv[])
{
    //定义变量存储线程号
    pthread_t tid = 1;

    //创建线程
    if (pthread_create(&tid, NULL, task, NULL) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx 线程号 = %#lx\n", tid, pthread_self());

    // //阻塞回收分支线程的资源
    // if(pthread_join(tid,NULL) == 0)
    // {
    //     printf("成功回收%#lx的资源\n",tid);
    // }

    //将线程设置成分离态
    pthread_detach(tid);
   

    
    sleep(5);
    //向分支线程发送取消请求
    pthread_cancel(tid);
    printf("线程已退出\n");

    //阻塞函数  主线程结束进程结束,分支线程也终止
    getchar();

    return 0;
}

pthread_sercancelstate:设置取消属性

       #include <pthread.h>

       int pthread_setcancelstate(int state, int *oldstate);
    功能:设置是否接收取消指令
    参数1:新的状态
        PTHREAD_CANCEL_ENABLE:可接受状态
        PTHREAD_CANCEL_DISABLE:不可接收状态
    参数2:线程的旧的状态容器,如果不愿意要之前的状态,填NULL即可
    返回值:成功返回0,失败返回错误码

#include <myhead.h>

void *task(void *arg)
{
    //设置线程不可取消状态
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    
    int n =0;
    while (1)
    {
        printf("子线程 线程号 = %#lx\n", pthread_self());
        n++;
        sleep(1);
        if (n == 10)
        {
            break;
        }
        
    }
    
    
    
    //exit(EXIT_SUCCESS);  //再线程中进程退出  主线程也会结束
    pthread_exit(NULL);  //线程退出 不影响主线程
}

int main(int argc, char const *argv[])
{
    //定义变量存储线程号
    pthread_t tid = 1;

    //创建线程
    if (pthread_create(&tid, NULL, task, NULL) != 0)
    {
        printf("pthread error");
        return -1;
    }

    printf("主线程 tid = %#lx 线程号 = %#lx\n", tid, pthread_self());

    // //阻塞回收分支线程的资源
    // if(pthread_join(tid,NULL) == 0)
    // {
    //     printf("成功回收%#lx的资源\n",tid);
    // }

    //将线程设置成分离态
    pthread_detach(tid);
    printf("线程已退出\n");

    
    sleep(5);
    //向分支线程发送取消请求
    pthread_cancel(tid);

    //阻塞函数  主线程结束进程结束,分支线程也终止
    getchar();

    return 0;
}

多线程允许使用同一个线程体函数

#include <myhead.h>

void *task(void *arg)
{
    if (strcmp((char*)arg,"hello") == 0)
    {
        int num = 10;
        while (num--)
        {
            printf("线程1\n");
            sleep(1);
        }
        pthread_exit(NULL);
    }
    else if (strcmp((char*)arg,"world") == 0)
    {
        sleep(5);
        printf("     线程2\n");
       
    }
    pthread_exit(NULL);

}

int main(int argc, char const *argv[])
{
    pthread_t tid1,tid2;

    if (pthread_create(&tid1,NULL,task,"hello") != 0)
    {
        printf("tid1 error");
        return -1;
    }

    if (pthread_create(&tid2,NULL,task,"world") != 0)
    {
        printf("tid2 error");
        return -1;
    }

    //阻塞等待线程结束
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);


    return 0;
}

作业

1、使用两个线程完成两个文件的拷贝,分支线程1拷贝前一半,分支线程2拷贝后一半,1主线程回收两个分支线程的资源

#include <myhead.h>

// 定义结构体存储信息
struct Buf
{
    int len;
    int s;
    const char *o_file;
    const char *n_file;
};

// 拷贝函数
void copy_file(const char *srcfile, const char *destfile, int start, int len)
{
    // 以只读的形式打开源文件
    int sfd = open(srcfile, O_RDONLY);
    if (sfd == -1)
    {
        perror("open srcfile error");
        return;
    }

    // 以创建的形式打开目标文件
    int dfd = open(destfile, O_WRONLY);
    if (dfd == -1)
    {
        perror("open destfile error");
        return;
    }

    // 移动光标位置
    lseek(sfd, start, SEEK_SET);
    lseek(dfd, start, SEEK_SET);

    // 定义搬运工
    char buf[128] = "";
    int sum = 0; // 记录拷贝的总个数
    while (1)
    {
        // 从源文件中读取数据
        int res = read(sfd, buf, sizeof(buf));
        sum += res; // 将读取的个数累加

        if (res == 0 || sum > len) // 表示文件读取结束
        {
            write(dfd, buf, res - (sum - len)); // 父进程将最后一次拷贝结束
            break;
        }
        // 写入到目标文件中
        write(dfd, buf, res);
    }

    // 关闭文件
    close(sfd);
    close(dfd);

    printf("拷贝成功\n");
}

// 线程功能
void *task(void *arg)
{
    printf("线程开始\n");

    //读取数据
    int n = ((struct Buf *)arg)->len;
    int start = ((struct Buf *)arg)->s;
    printf("%d\n",start);
   
     //调用拷贝函数
    copy_file(((struct Buf *)arg)->o_file, ((struct Buf *)arg)->n_file, start, n);
    //线程退出
    pthread_exit(NULL);
}

int get_file_len(const char *o_file, const char *n_file)
{
    int ofd = open(o_file, O_RDONLY);
    if (ofd < 0)
    {
        perror("82ofd open error");
        exit(EXIT_SUCCESS);
    }

    umask(0000);

    int nfd = open(n_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (nfd < 0)
    {
        perror("89nfd open error");
        exit(EXIT_SUCCESS);
    }

    int len = lseek(ofd, 0, SEEK_END);

    close(ofd);
    close(nfd);

    return len;  
}

int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("终端输入错误\n");
        return -1;
    }

    struct Buf buf1, buf2; // 定义信息传输结构体

    int res = get_file_len(argv[1], argv[2]);

    buf1.len = res / 2;
    buf1.o_file = argv[1];
    buf1.n_file = argv[2];
    buf1.s = 0;

    buf2.len = res - res / 2;
    buf2.o_file = argv[1];
    buf2.n_file = argv[2];
    buf2.s = res / 2;

    pthread_t tid1, tid2;

    if (pthread_create(&tid1, NULL, task, &buf1) != 0)
    {
        printf("tid1 error");
        return -1;
    }


    if (pthread_create(&tid2, NULL, task, &buf2) != 0)
    {
        printf("tid2 error");
        return -1;
    }

    // 将线程设置成分离态
    pthread_detach(tid1);
    pthread_detach(tid2);
    printf("线程已退出\n");

    // 阻塞等待线程结束
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    printf("回收结束\n");
    getchar();

    return 0;
}

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

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

相关文章

检索增强生成(RAG):智能内容生成的新纪元

引言 在大 AI 时代&#xff0c;生成式人工智能&#xff08;GenAI&#xff09;模型&#xff0c;尤其是大型语言模型&#xff08;LLM&#xff09;&#xff0c;已经展现出了令人瞩目的能力。然而&#xff0c;这些模型在提供信息的准确、即时、专业、权威等方面仍存在局限。检索增…

1.2、安装k8s-node1 和 k8s-node2节点虚拟机

k8s-master节点的虚拟机环境弄好之后&#xff0c;这小节继续介绍k8s-node1 和 k8s-node2节点虚拟机环境安装。 节点主机名ip主节点k8s-master172.31.0.10节点1k8s-node1172.31.0.11节点2k8s-node2172.31.0.12 在D:\vagrant目录下新建centos_stream_9_node1文件夹&#xff0c;然…

如何在Python中使用网页抓取API获得Google搜索结果

SERP是搜索引擎结果页的缩写&#xff0c;它是你在百度、谷歌、Bing等搜索引擎中提交查询后所得到的页面。搜索引擎需要给所有页面做排序&#xff0c;把最能解决我们需求的页面展示给我们&#xff0c;企业会非常关注结果页的排序&#xff0c;也就是本企业内容的自然排名情况。手…

革新IT架构管理,宝兰德全新中间件统一管理平台助力企业数字化转型

近期&#xff0c;宝兰德在金融行业科技盛会“2024中国国际金融展”上正式发布了拳头产品「中间件统一管理平台MCP2.0」&#xff0c;旨在推动业务与中间件解耦&#xff0c;解决中间件管理中的版本不统一、自动化程度低、监控不完善、运维效率低、管理分散等问题&#xff0c;实现…

8月1日学习笔记 java环境安装以及tomcat配置

一&#xff0c;java环境安装 1. 效果 2. 步骤 1. 下载 jdk22 # 官网地址 https://www.oracle.com/cn/java/technologies/download s/ wget https://download.oracle.com/java/22/latest/jdk- 22_linux-x64_bin.tar.gz 2. 解压 tar -zxvf jdk-22.2.tar.gz 3. 移动到 us…

快速搞定分布式Kafka

本文从kafka中的实际应用场景分析&#xff0c;讲述kafka的一些基本概念。再讲述zookeeper集群环境的构建&#xff1b;kafka的搭建以及脚本文件编写&#xff1b;最后是一个快速入门的demo.内容会比较多&#xff0c;希望大家能有所收获&#xff01; 1.Kafka(MQ)实战应用场景剖析…

linux系统ShellCheck检查shell脚步语法正确的工具

目录 ShellCheck 安装ShellCheck 、dnf、yum 源代码编译 步骤如下&#xff1a; 示例命令&#xff1a; 方法三&#xff1a;使用其他第三方仓库、COPR 仓库 假设 ShellCheck 输出如下&#xff1a; 分析输出 修改脚本 再次运行 ShellCheck 1. Shell 脚本最佳实践 主题…

vcpkg install libtorch[cuda] -allow-unsupported-compiler

在vcpkg中不懂如何使用 nvcc 的 -allow-unsupported-compiler, 所以直接注释了CUDA中对版本的检查代码. C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\include\crt\host_config.h 奇了怪了,我是用的是vs2022,但是还是被检查为不支持的编译器!!! 可以试一下改这…

搭建gitlab代码托管仓库(解决centos7无法使用默认数据源问题)

公司的gitlab由于停电&#xff0c;又崩了&#xff0c;每次停电都会崩掉。所以就想到自己学一下搭建gitlab代码中心&#xff0c;后面在搞一个jenkins自动发版学习一下&#xff0c;慢慢搞吧。 在弄的时候&#xff0c;发现Centos7居然在2024年6月31日停止维护了。这就离谱了&…

职教国培丨高职教师数据分析与挖掘课程实施能力提升培训班莅临泰迪智能科技参观调研

7月28日&#xff0c;由广东机电职业技术学院牵头&#xff0c;广东泰迪智能科技股份有限公司为合作单位的“2024年高职教师数据分析与挖掘课程实施能力提升培训班”老师莅临广东泰迪智能科技股份有限公司产教融合实训基地参观调研&#xff0c;来自广东省各地36位高校教师参与本次…

如何在 Kali Linux 上安装和使用 Docker 和 Docker Compose

Docker 和 Docker Compose 是现代开发者必备的工具&#xff0c;特别是当你需要在不同的环境中部署应用时。本文将详细介绍如何在 Kali Linux 上安装 Docker 和 Docker Compose&#xff0c;并使用它们启动服务。即使你是个技术小白&#xff0c;也能轻松跟随这篇指南完成操作。 …

Ecovadis认证:企业申请Ecovadis认证条件

Ecovadis认证是一种用于评估和评价企业可持续发展绩效的认证体系。该认证由Ecovadis公司提供&#xff0c;目的是帮助公司了解和改善其环境、社会和治理&#xff08;ESG&#xff09;实践。 Ecovadis认证主要基于四个方面进行评估&#xff1a;环境、劳工和人权、道德采购以及可持…

Python——记录pip问题(解决下载慢、升级失败问题)

在python开发中&#xff0c;经常需要使用到各种各样的库。 pip又是我们常用的安装工具。但是国外的源下载速度实在太慢&#xff0c;经常导致超时。 有很多朋友刚刚学Python的时候&#xff0c;会来问为什么pip下载东西这么慢啊&#xff1f; 而且pycharm里面下载库也是非常的慢…

Linux服务器安装MySQL8.0

序号类型地址1MySQLLinux&#xff08;centos 7.5&#xff09;服务器安装MySQL5.72MySQLLinux服务器安装MySQL8.03MySQLMySQL操作之概念、SQL约束&#xff08;一&#xff09;4MySQLMySQL操作之数据定义语言&#xff08;DDL)&#xff08;二&#xff09;5MySQLMySQL操作之数据操作…

React三原理和路由

代码下载 React 组件通讯原理 setState() 说明 setState() 是异步更新数据的&#xff0c;使用该语法时&#xff0c;后面的 setState() 不要依赖于前面的 setState()&#xff0c;可以多次调用 setState() &#xff0c;只会触发一次重新渲染&#xff1a; this.setState({ coun…

CPQ报价管理系统 | 成本报价CPQ解决方案

一、成本报价流程现状 1、传统流程 2、业务痛点 ①、数据手工重复输入环节多、易错&#xff0c;为保障准确性需多次复核&#xff0c;影响报价效率 ②、原材波动较大&#xff0c;但是当前询价流程只有一次性&#xff0c;原材成本发生变化&#xff0c;无法及时更新变化提醒报价…

类和对象(作业篇)

简简单单整理一下咱们的小作业&#xff0c;这次的作业比较简单&#xff0c;只有选择题&#xff1a; public class Test{private float f1.0f;int m12;static int n1;public static void main(String args[]){Test tnew Test();} }A&#xff1a;抛开private不说&#xff0c;先看…

解析顺序表【数据结构】

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有线序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;也就是说是连续的一条线…

HTML 字符集详解及示例

文章目录 摘要引言从ASCII到UTF-8的演变ASCII 字符集ANSI字符集ISO-8859-1字符集UTF-8字符集 示例代码运行Demo小结表格总结未来展望参考资料 摘要 本文介绍了HTML中的字符集演变历史&#xff0c;从最初的ASCII到现代的UTF-8&#xff0c;并提供了设置字符集的示例代码。文中涵…

图形编辑器基于Paper.js教程10:导入导出svg,导入导出json数据

深入了解Paper.js&#xff1a;实现SVG和JSON的导入导出功能 Paper.js是一款强大的矢量绘图JavaScript库&#xff0c;非常适合用于复杂的图形处理和交互式网页应用。本文将详细介绍如何在Paper.js项目中实现SVG和JSON格式的导入导出功能&#xff0c;这对于开发动态图形编辑器等…