2024.6.12 1.将父子进程拷贝图片进行修改 2.分析错误3.用线程的方式拷贝图片

1.父子进程的代码单独分离到其他的可执行二进制程序用,用exec函数族进行组合。

        提示:学习使用sprintf函数 atoi函数。

主代码

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, const char *argv[])
{

	int cfp=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0770);//提前创建好复制的空壳文件,并清空


	pid_t pid=fork();//创建子进程

	int fp=open("./qq.png",O_RDONLY);//打开被复制的文件
	off_t size = lseek(fp,0,SEEK_END);//获取文件大小
	off_t size_head = size / 2;
	char c;
	ssize_t num;

	lseek(fp,0,SEEK_SET);//将文件偏移修改到文件头

	printf("pid=%d\n",pid);
	if(pid!=0)
	{
		while(1)
		{
			num = read(fp,&c,1);
			write(cfp,&c,num);
			if(lseek(fp,0,SEEK_CUR)==size_head)
			{
				printf("前半部分复制完成\n");
				break;
			}
		}

		int wstatus;
		wait(&wstatus);//等待子进程结束
	}
	else if(pid == 0)
	{
		//sleep(1);
		char str[20];
		sprintf(str,"%ld",size_head);
		execl("./copy.out","./copy.out",str,NULL);
	}


	close(cfp);
	close(fp);
	return 0;
}

分离区代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	char str[20]={0};
	strcpy(str,argv[1]);
	char c;
	int num = atoi(str);//获取被复制图片前半部分的大小
	//	printf("num = %d\n",num);

	int fp=open("./qq.png",O_RDONLY);//打开被复制的文件
	int cfp=open("./copy.png",O_WRONLY);

	lseek(fp,num,SEEK_SET);
	lseek(cfp,num,SEEK_SET);

	while(1)
	{
		num = read(fp,&c,1);//num没有用了,重新赋值
		write(cfp,&c,num);
		if(num==0)
		{
			printf("后半部分复制完成\n");
			break;
		}

	}

	close(cfp); 
	close(fp);
	exit(0);
	return 0;
}

运行结果

2.要求定义一个全局变量 char buf[] = "1234567",创建两个线程,不考虑退出条件。

A线程循环打印buf字符串,

B线程循环倒置buf字符串,即buf中本来存储1234567,倒置后buf中存储7654321. B线程中不打印!!倒置不允许使用辅助数组。

要求A线程打印出来的结果只能为 1234567 或者 7654321 不允许出现7634521 7234567等乱序情况

不允许使用sleep函数

分析出现错误的原因。

代码

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

char buf[]="1234567";//创建全局变量

void* Filp_over(void* arg)//B线程,循环倒置buf
{
	int len = strlen(buf),head = 0,tail = len-1;
	char temp;
	while(1)
	{
		if(head == tail || head > tail)
		{
			head = 0;
			tail = len-1;
		//	printf("FIlp=%s\n",buf);
		//	sleep(3);
		}
		temp = buf[head];
		buf[head] = buf[tail];
		buf[tail] = temp;
		head++;
		tail--;
	}
}

int main(int argc, const char *argv[])//A线程,循环打印
{
	//创建线程
	pthread_t tid;//用于接收创建的线程号
	if(pthread_create(&tid,NULL,Filp_over,NULL)!=0)//创建成功返回0,错误返回错误码
	{
		fprintf(stderr,"create pthread on error\n");
		return -1;
	}

	while(1)
	{
		printf("buf=%s\n",buf);
	//	sleep(1);
	}

	return 0;
}

运行结果

分析错误

从运行结果中可以看出来:A线程循环打印buf竟然出现了重复值。这可能是因为A线程和B线程共享附属进程的资源,B线程运行到中间时分配给他的资源结束,回到A线程打印。

可以看见打印出来的整个字符串也出现重复,这可能是因为A线程运行时,B线程没有运行,再一次证明了linux以时间片轮回方式运行。

3.用线程完成图片拷贝,要求一个线程拷贝一半,另一个线程拷贝另一半。

代码

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void* copy_tail(void* arg)
{
	off_t size = *(int*)arg;//接收被复印文件一半的大小,作为复印和被复印下半部分的起始点

	//打开被复印的文件
	int fp = open("./qq.png",O_RDONLY);

	//打开需要复印的文件,因为在创建子线程前就已经创建清空过了,这里千万不要清空,以写的方式打开即可
	int cfp = open("./pict.png",O_WRONLY);
	
	//修改文件偏移量,以便能正确复印
	lseek(fp,size,SEEK_SET);
	lseek(cfp,size,SEEK_SET);

	ssize_t size_len;
	char c;
	while(1)
	{
		size_len = read(fp,&c,sizeof(c));
		write(cfp,&c,size_len);
		//这里只要打印到文件末尾即可结束循环,无需考虑文件大小的奇偶性
		if(0==size_len)
		{
			printf("后半部分打印完成\n");
			break;
		}
	}

	close(cfp);
	close(fp);

	//为了防止主线程比在子线程未结束时就提前结束,造成后半部分打印出错
	//这里用pthread_exit(),在主线程用pthread_join()阻塞,等待子线程结束即可
	pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
	//创建,清空文件
	int cfp = open("./pict.png",O_WRONLY|O_CREAT|O_TRUNC,0775);

	//打开被复制的文件
	int fp = open("./qq.png",O_RDONLY);

	//计算文件大小并且取一半
	off_t size = (lseek(fp,0,SEEK_END))/2;

	//将文件偏移量重新移到开头
	lseek(fp,0,SEEK_SET);

	//创建线程
	pthread_t tid ;
	if(pthread_create(&tid,NULL,copy_tail,(void*)&size)!=0)
	{
		fprintf(stderr,"creat pthread on error\n");
		close(cfp);
		close(fp);
		return -1;
	}
	ssize_t size_len;
	char c;
	while(1)//复制前半部分
	{
		size_len = read(fp,&c,sizeof(c));
		write(cfp,&c,size_len);
		if(lseek(fp,0,SEEK_CUR)==size)
		{
			printf("前半部分打印完成\n");
			break;
		}

	}

	close(cfp);
	close(fp);

	//阻塞,等待子线程结束
	pthread_join(tid,NULL);
	return 0;
}

运行结果

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值