【练】创建两个线程:其中一个线程拷贝图片的前半部分,另一个线程拷贝后半部分

方法一:

        先在主函数创建并清空拷贝的目标文件,再创建两个线程,在两个线程内部同时打开要读取的文件以及要拷贝的目标文件(两个线程不共用同一份资源)。

使用到的函数:

  1. 标准IO函数(fprintf)【用于打印错误信息】
  2. 文件IO函数(open、close、lseek)
  3. 有关线程的函数(pthread_create、pthread_exit、pthread_join)
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <head.h>
//线程的执行体
void* callback_1(void* arg)   //void* arg = (void*)&c
{
    umask(0);
    int fp_r=open("./1.png",O_RDONLY);                                               
    if(fp_r < 0)
    {
        ERR_MSG("open");
    }
    int fp_w=open("./copy.png",O_WRONLY);
    if(fp_w <0)
    {
        ERR_MSG("open");
    }
    char c = 0;
    off_t len=lseek(fp_r,0,SEEK_END);
    int i=0;
    lseek(fp_r,0,SEEK_SET);
    lseek(fp_w,0,SEEK_SET);
    for(i=0;i<len/2;i++)
    {
        bzero(&c,sizeof(c));
        read(fp_r,&c,1);
        write(fp_w,&c,1);
    }

    close(fp_r);
    close(fp_w);

    printf("前半部分拷贝完毕\n");
    pthread_exit(NULL);
}
void* callback_2(void* arg)
{
    umask(0);
    int fp_r=open("./1.png",O_RDONLY);
    if(fp_r < 0)
    {
        ERR_MSG("open");
    }
    int fp_w=open("./copy.png",O_WRONLY);
    if(fp_w < 0)
    {
        ERR_MSG("open");
    }
    char c = 0;
    off_t len=lseek(fp_r,0,SEEK_END);
    int i=0;
    lseek(fp_r,len/2,SEEK_SET);
    lseek(fp_w,len/2,SEEK_SET);
    for(i=0;i<len/2;i++)
    {
        bzero(&c,sizeof(c));
        read(fp_r,&c,sizeof(c));
        write(fp_w,&c,sizeof(c));
    }

    close(fp_r);
    close(fp_w);
    printf("后半部分拷贝完毕\n");
    pthread_exit(NULL);

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

    pthread_t tid_1,tid_2;
    if(pthread_create(&tid_1,NULL,callback_1,NULL) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
        return -1;
    }

    pthread_join(tid_1,NULL);

    if(pthread_create(&tid_2,NULL,callback_2,NULL)!=0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
        return -1;
    }

    pthread_join(tid_2,NULL);
    printf("主线程准备退出... ...\n");
    return 0;
}
                                                                                     
                                                                                    

方法二:

        创建一个结构体用于存放需要打开的两个文件文件标识符、需要拷贝的字节大小。

        在主函数中打开两个文件,计算好需要拷贝的字节大小,再创建两个线程,将结构体fileinfo的地址传递到线程中(强转成(void*)类型再传,否则报错),线程中用指针void* arg接fileinfo的地址。线程中需要将指针arg的地址转为struct Msg类型。

        PS:两个线程共享同一份资源,使用pthread_exit函数使线程1先完成拷贝(与sleep达到的效果一致)。

使用到的函数:

  1. 结构体struct
  2. 标准IO函数(fprintf)【用于打印错误信息】
  3. 文件IO函数(open、close、lseek)
  4. 有关线程的函数(pthread_create、pthread_exit、pthread_join)
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <head.h>
struct Msg
{
	int fp_r;
	int fp_w;
	off_t size;
};
//线程1的执行体:拷贝前半部分
void* callback_1(void* arg)   //void* arg = &fileinfo
{
	struct Msg *tp=(struct Msg*)arg;
	int fp_r=tp->fp_r;
	int fp_w=tp->fp_w;
	off_t size=tp->size;
	
	//将光标偏移到开头,拷贝size/2个字节到目标文件中
	lseek(fp_r,0,SEEK_SET);
	lseek(fp_w,0,SEEK_SET);
	char c = 0;
	for(int i=0;i<size/2;i++)
	{
		bzero(&c,sizeof(c));
		read(fp_r,&c,1);
		write(fp_w,&c,1);
	}
	printf("前半部分拷贝完毕\n");
	pthread_exit(NULL);//退出分支线程
}
//线程2的执行体
void* callback_2(void* arg)  //void* arg = &fileinfo
{
	//sleep(5);//主动放弃cpu资源,让线程1先执行
	struct Msg *tp=(struct Msg*)arg;
	int fp_r=tp->fp_r;
	int fp_w=tp->fp_w;
	off_t size=tp->size;

	//将光标偏移到size/2的位置,拷贝size/2个字节到目标文件中
	lseek(fp_r,size/2,SEEK_SET);
	lseek(fp_w,size/2,SEEK_SET);
	char c = 0;
	for(int i=0;i<size/2;i++)
	{
		bzero(&c,sizeof(c));
		read(fp_r,&c,sizeof(c));
		write(fp_w,&c,sizeof(c));
	}
	printf("后半部分拷贝完毕\n");
	pthread_exit(NULL);//退出分支线程
}
int main(int argc, const char *argv[])
{
	struct Msg fileinfo;
	//以读的方式打开1.png
	fileinfo.fp_r=open("./1.png",O_RDONLY);
	if(fileinfo.fp_r < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	//以写的方式打开并创建(若存在则清空)copy.png
	fileinfo.fp_w=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fileinfo.fp_w <0)
	{
		ERR_MSG("open");
		return -1;
	}
	//计算需要拷贝的字节大小
	fileinfo.size=lseek(fileinfo.fp_r,0,SEEK_END);

	//创建2个线程
	pthread_t tid_1,tid_2;
	if(pthread_create(&tid_1,NULL,callback_1,(void *)&fileinfo) != 0)
	{
		fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
		return -1;
	}
	pthread_join(tid_1,NULL);//阻塞等待线程1完成

	if(pthread_create(&tid_2,NULL,callback_2,(void *)&fileinfo) !=0)
	{
		fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
		return -1;
	}
	pthread_join(tid_2,NULL);//阻塞等待线程2完成

	//关闭文件
	close(fileinfo.fp_r);
	close(fileinfo.fp_w);
	printf("主线程准备退出\n");
	return 0;
}

方法三:

       创建一个结构体用于存放需要打开的两个文件文件标识符、需要拷贝的字节大小。

        PS:两个线程共享同一份资源,利用互斥锁完成任务。

使用到的函数:

  1. 结构体struct
  2. 标准IO函数(fprintf)【用于打印错误信息】
  3. 文件IO函数(open、close、lseek)
  4. 有关线程的函数(pthread_create、pthread_exit、pthread_join)
  5. 互斥锁(创建互斥锁pthread_mutex_init、上锁pthread_mutex_lock、解锁pthread_mutex_unlock、销毁互斥锁pthread_mutex_destroy)
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <head.h>
//临界资源
struct Msg
{
	int fp_r;
	int fp_w;
	off_t size;
	pthread_mutex_t mutex;//互斥锁
};
//线程1的执行体:拷贝前半部分
void* callback_1(void* arg)   //void* arg = &fileinfo
{
	struct Msg *fileinfo=(struct Msg*)arg;

	/************************临界区***************************/
	//上锁
	pthread_mutex_lock(&fileinfo->mutex);

	int fp_r=fileinfo->fp_r;
	int fp_w=fileinfo->fp_w;
	off_t size=fileinfo->size;

	
	//将光标偏移到开头,拷贝size/2个字节到目标文件中
	lseek(fp_r,0,SEEK_SET);
	lseek(fp_w,0,SEEK_SET);
	char c = 0;
	for(int i=0;i<size/2;i++)
	{
		bzero(&c,sizeof(c));
		read(fp_r,&c,1);
		write(fp_w,&c,1);
	}
	printf("前半部分拷贝完毕\n");
	
	//解锁
	pthread_mutex_unlock(&fileinfo->mutex);
	/************************临界区***************************/
	pthread_exit(NULL);//退出分支线程
}
//线程2的执行体
void* callback_2(void* arg)  //void* arg = &fileinfo
{
	struct Msg *fileinfo=(struct Msg*)arg;
	/************************临界区***************************/
	//上锁
	pthread_mutex_lock(&fileinfo->mutex);

	int fp_r=fileinfo->fp_r;
	int fp_w=fileinfo->fp_w;
	off_t size=fileinfo->size;

	//将光标偏移到size/2的位置,拷贝size/2个字节到目标文件中
	lseek(fp_r,size/2,SEEK_SET);
	lseek(fp_w,size/2,SEEK_SET);
	char c = 0;
	for(int i=0;i<size/2;i++)
	{
		bzero(&c,sizeof(c));
		read(fp_r,&c,sizeof(c));
		write(fp_w,&c,sizeof(c));
	}
	printf("后半部分拷贝完毕\n");
	//解锁
	pthread_mutex_unlock(&fileinfo->mutex);
	/************************临界区***************************/
	pthread_exit(NULL);//退出分支线程
}
int main(int argc, const char *argv[])
{
	struct Msg fileinfo;
	//以读的方式打开1.png
	fileinfo.fp_r=open("./1.png",O_RDONLY);
	if(fileinfo.fp_r < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	//以写的方式打开并创建(若存在则清空)copy.png
	fileinfo.fp_w=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fileinfo.fp_w <0)
	{
		ERR_MSG("open");
		return -1;
	}
	//计算需要拷贝的字节大小
	fileinfo.size=lseek(fileinfo.fp_r,0,SEEK_END);
	//申请一个互斥锁
	pthread_mutex_init(&fileinfo.mutex,NULL);
	
	//创建2个线程
	pthread_t tid_1,tid_2;
	if(pthread_create(&tid_1,NULL,callback_1,(void *)&fileinfo) != 0)
	{
		fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
		return -1;
	}
	pthread_detach(tid_1);  //分离线程1
 
	if(pthread_create(&tid_2,NULL,callback_2,(void *)&fileinfo) !=0)
	{
		fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
		return -1;
	}
	pthread_join(tid_2,NULL);//阻塞等待线程2完成
 
	//关闭文件
	close(fileinfo.fp_r);
	close(fileinfo.fp_w);
	printf("主线程准备退出\n");
	//销毁互斥锁
	pthread_mutex_destroy(&fileinfo.mutex);
	return 0;
}

 

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

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

相关文章

C++模板

目录 一.泛型编程 二.模板 1.函数模板 1.1函数模板格式&#xff1a; 1.2函数模板的原理 1.3 函数模板的实例化 隐式实例化 显式实例化 &#xff1a; 模板参数的匹配原则&#xff1a; 2.类模板 2.1类模板格式 一.泛型编程 如何实现一个通用的交换函数呢&#xff1f;…

主动带宽控制工具

停机和带宽过度使用是任何组织都无法避免的两个问题。随着企业采用 BYOD 文化&#xff0c;通过网络的流量负载可能很重&#xff0c;导致网络拥塞并使网络容易受到网络攻击。为了解决这个问题&#xff0c;企业需要全面的监控策略来保护网络&#xff0c;当看似大量的流量进入网络…

C++学习——模板

目录 &#x1f349;一&#xff1a;什么是模板 &#x1f34e;二&#xff1a;普通模板的定义 &#x1f34d;三&#xff1a;类模板的定义 &#x1f34c;四&#xff1a;模板的实例化 &#x1f347;1.当普通模板定义存在可修改返回值产生的分歧 &#x1f348;2&#xff1a;类模板实例…

一文读透时区和时间戳以及基于Java的操作

重要概念 1. UTC 和 UTC8 UTC 是世界标准时间&#xff0c; UTC8 是东八区标准时间&#xff0c;中国就属于东八区&#xff0c; 也就是北京时间。 8 就是加8个小时。 时区的划分图示如下&#xff1a; 也就是说&#xff1a; 假如现在是UTC时间是 2023-08-08 01:00:00 &#xff0…

MySQL数据库——多表操作

文章目录 前言多表关系一对一关系一对多/多对一关系多对多关系 外键约束创建外键约束插入数据删除带有外键约束的表的数据删除外键约束 多表联合查询数据准备交叉连接查询内连接查询外连接查询左外连接查询右外连接查询满外连接查询 子查询子查询关键字ALL 关键字ANY 和 SOME 关…

k8s kubeadm命令升级集群 从1.17升级到1.18

k8s kubeadm命令升级集群 从1.17升级到1.18 大纲 注意事项master节点执行升级命令master节点和node节点执行命令 注意事项 目标当前线上k8s集群版本是k8s1.17 想把k8s升级到1.18。注意k8s不能跨版本升级例如k8s1.17不能直接升级到k8s1.19&#xff0c;需要先升级到1.18才后向…

【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

dubbo的高可用

1、zookeeper宕机与dubbo直连 现象&#xff1a;zookeeper注册中心宕机&#xff0c;还可以消费dubbo暴露的服务。 原因&#xff1a; 健壮性 &#xff08;1&#xff09;监控中心宕掉不影响使用&#xff0c;只是丢失部分采样数据. &#xff08;2&#xff09;数据库宕掉后&#x…

springboot访问请求404的原因

是记录&#xff0c;可能出现错误 可能出现的原因 1.你请求的URL路径不对,比如说你请求的路径是/usr/list,GET方法,但是你UserController上面的RequestMapping是这个样子:RequestMapping(“user”)&#xff0c;有可能哈 2.前端的请求时GET方法&#xff0c;后端对应的处理函数的方…

C++ 指针数组

如果一个数组的每个元素都是指针变量&#xff0c;这个数组就是指针数组。指针数组的每个元素都必须是同一类型的指针。 1.一维指针数组 声明一维指针数组的语法形式&#xff1a; 数据类型*数组名[下标表达式];下标表达式指出数组元素的个数&#xff0c;数据类型确定每个元素…

Kafka3.0.0版本——生产者如何提高吞吐量

目录 一、生产者提高吞吐量参数设置二、产者提高吞吐量代码示例 一、生产者提高吞吐量参数设置 batch.size&#xff1a;设置批次大小&#xff0c;默认16klinger.ms&#xff1a;设置等待时间&#xff0c;修改为5-100msbuffer.memory&#xff1a;设置缓冲区大小&#xff0c; 默认…

信号槽中的函数重载

信号槽中的函数重载 QT4的方式QT5的方式函数指针重载函数QT5信号函数重载解决方案 总结 QT4的方式 Qt4中声明槽函数必须要使用 slots 关键字, 不能省略。 信号函数&#xff1a; 槽函数&#xff1a; mainwondow: cpp文件&#xff1a; #include "mainwindow.h"…

快速部署外卖系统:利用现代工具简化开发流程

在竞争激烈的外卖市场中&#xff0c;快速部署高效稳定的外卖系统是餐饮企业成功的关键之一。本文将介绍如何利用现代工具简化外卖系统的开发流程&#xff0c;并附带代码示例&#xff0c;帮助开发者快速搭建功能完备、用户友好的外卖平台。 1. 简介 在外卖业务快速增长的背景…

使用express搭建后端服务

目录 1 创建工程目录2 初始化3 安装express依赖4 启动服务5 访问服务总结 上一篇我们利用TDesign搭建了前端服务&#xff0c;现在的开发讲究一个前后端分离&#xff0c;后端的话需要单独搭建服务。后端服务的技术栈还挺多&#xff0c;有java、php、python、nodejs等。在众多的技…

稍微深度踩坑haystack + whoosh + jieba

说到django的全文检索&#xff0c;网上基本推荐的都是 haystack whoosh jieba 的方案。 由于我的需求对搜索时间敏感度较低&#xff0c;但是要求不能有数据的错漏。 但是没有调试的情况下&#xff0c;搜索质量真的很差&#xff0c;搞得我都想直接用Like搜索数据库算了。 但是…

排序八卦炉之冒泡、快排

文章目录 1.冒泡排序1.1代码实现1.2复杂度 2.快速排序2.1人物及思想介绍【源于百度】2.2hoare【霍尔】版本1.初识代码2.代码分析3.思其因果 3.相关博客 1.冒泡排序 1.1代码实现 //插入排序 O(N)~O(N^2) //冒泡排序 O(N)~O(N^2) //当数据有序 二者均为O(N) //当数据接近有序或…

什么是 webpack?

Webpack 介绍 什么是 webpack&#xff1f; :::tip 官方描述 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个…

第四章 数据库安全性

问题的提出 &#xff08;1&#xff09;数据库的一大特点是数据可以共享 &#xff08;2&#xff09;数据共享必然带来数据库的安全性问题 &#xff08;3&#xff09;数据库系统中的数据共享不能是无条件的共享 这就引发了数据库安全性问题 1.数据库安全性概述 数据库的安全性…

MySQL日志——查询日志

1.查询日志 show variables like %general%;修改mysql的配置文件 /etc/my.cnf文件&#xff0c;添加如下内容&#xff1a; #该选项用来开启查询日志&#xff0c;可选值&#xff1a;0或者1&#xff1b;0代表关闭&#xff0c;1代表开启 general_log1 #设置日志的文件名&#xff0…

C# Blazor 学习笔记(8):row/col布局开发

文章目录 前言相关文章代码row和col组件B_rowB_col结构 使用 前言 可能是我用的element ui和 uView这种第三方组件用的太多了。我上来就希望能使用这些组件。但是目前Blazor目前的生态其实并不完善&#xff0c;所以很多组件要我们自己写。 我们对组件的要求是 我们在组件化一共…