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;
}
运行结果