方法一:使用pthread_create、pthread_exit、pthread_join函数【两个线程不共用同一份资源】
先在主函数创建并清空拷贝的目标文件,再创建两个线程,在两个线程内部同时打开要读取的文件以及要拷贝的目标文件(两个线程不共用同一份资源)。
使用到的函数:
- 标准IO函数(fprintf)【用于打印错误信息】
- 文件IO函数(open、close、lseek)
- 有关线程的函数(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达到的效果一致)。
使用到的函数:
- 结构体struct
- 标准IO函数(fprintf)【用于打印错误信息】
- 文件IO函数(open、close、lseek)
- 有关线程的函数(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:两个线程共享同一份资源,利用互斥锁完成任务。
使用到的函数:
- 结构体struct
- 标准IO函数(fprintf)【用于打印错误信息】
- 文件IO函数(open、close、lseek)
- 有关线程的函数(pthread_create、pthread_exit、pthread_join)
- 互斥锁(创建互斥锁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>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//临界资源
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;
int fp_r=fileinfo->fp_r;
int fp_w=fileinfo->fp_w;
off_t size=fileinfo->size;
char c = 0;
/************************临界区***************************/
//上锁
pthread_mutex_lock(&fileinfo->mutex);
//将光标偏移到开头,拷贝size/2个字节到目标文件中
lseek(fp_r,0,SEEK_SET);
lseek(fp_w,0,SEEK_SET);
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;
int fp_r=fileinfo->fp_r;
int fp_w=fileinfo->fp_w;
off_t size=fileinfo->size;
char c = 0;
/************************临界区***************************/
//上锁
pthread_mutex_lock(&fileinfo->mutex);
//将光标偏移到size/2的位置,拷贝size/2个字节到目标文件中
lseek(fp_r,size/2,SEEK_SET);
lseek(fp_w,size/2,SEEK_SET);
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);//退出分支线程
}
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_1,NULL);//阻塞等待线程1完成
pthread_join(tid_2,NULL);//阻塞等待线程2完成
//销毁互斥锁
pthread_mutex_destroy(&fileinfo.mutex);
//关闭文件
close(fileinfo.fp_r);
close(fileinfo.fp_w);
printf("主线程准备退出\n");
return 0;
}
错误:将线程1分离
#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;
}
方法四:互斥锁【两个线程共享同一份资源】
创建一个结构体用于存放需要打开的两个文件文件标识符、需要拷贝的字节大小;将互斥锁初始化。
达到的效果:
- 记录拷贝的位置,给偏移量和offset上锁。记录完fooset的数据后解锁
- 可两个线程切换拷贝
PS:两个线程共享同一份资源,利用互斥锁完成任务。
使用到的函数:
- 结构体struct
- 标准IO函数(fprintf)【用于打印错误信息】
- 文件IO函数(open、close、lseek)
- 有关线程的函数(pthread_create、pthread_exit、pthread_join)
- 互斥锁(创建互斥锁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>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//临界资源
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;
int fp_r=fileinfo->fp_r;
int fp_w=fileinfo->fp_w;
off_t size=fileinfo->size;
char c = 0;
off_t offset=0;
for(int i=0;i<size/2;i++)
{
/******************临界区*******************/
//上锁
pthread_mutex_lock(&fileinfo->mutex);
//将光标偏移到开头,拷贝size/2个字节到目标文件中
lseek(fp_r,offset,SEEK_SET);
lseek(fp_w,offset,SEEK_SET);
read(fp_r,&c,1);
write(fp_w,&c,1);
offset=lseek(fp_r,0,SEEK_CUR);
//解锁
pthread_mutex_unlock(&fileinfo->mutex);
/****** ************临界区*******************/
}
printf("前半部分拷贝完毕\n");
pthread_exit(NULL);//退出分支线程
}
//线程2的执行体
void* callback_2(void* arg) //void* arg = &fileinfo
{
struct Msg *fileinfo=(struct Msg*)arg;
int fp_r=fileinfo->fp_r;
int fp_w=fileinfo->fp_w;
off_t size=fileinfo->size;
char c = 0;
off_t offset=size/2;
for(int i=0;i<size/2;i++)
{
/*******************临界区*******************/
//上锁
pthread_mutex_lock(&fileinfo->mutex);
//将光标偏移到size/2的位置,拷贝size/2个字节到目标文件中
lseek(fp_r,offset,SEEK_SET);
lseek(fp_w,offset,SEEK_SET);
read(fp_r,&c,1);
write(fp_w,&c,1);
offset=lseek(fp_r,0,SEEK_CUR);
//解锁
pthread_mutex_unlock(&fileinfo->mutex);
/******************临界区*********************/
}
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);
//申请一个互斥锁
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;
}
if(pthread_create(&tid_2,NULL,callback_2,(void *)&fileinfo) !=0)
{
fprintf(stderr, "pthread_create failed __%d__\n",__LINE__);
return -1;
}
pthread_join(tid_1,NULL);//阻塞等待线程2完成
pthread_join(tid_2,NULL);//阻塞等待线程2完成
//销毁互斥锁
pthread_mutex_destroy(&fileinfo.mutex);
//关闭文件
close(fileinfo.fp_r);
close(fileinfo.fp_w);
printf("主线程准备退出\n");
return 0;
}