2017-07-14
今日是培训的第七天。
(不要问我为什么总写这句看似很low的话,这是一个程序员的修养)
今日,老师主要还在回顾一些之前的内容,新课讲的并不是很多。我就来show一下自己写的东西吧。
这是一个在Linux下的多线程将文件A的内容拷贝文件B中的程序
- 头文件部分:
#include <stdio.h>
#include <fcntl.h> //用来避免一些系统安全问题
#include <sys/types.h> //类型
#include <stdlib.h>
#include <unistd.h> //unix的一些系统调用
#include <time.h>
#include <pthread.h> //多线程头文件
#include <sys/stat.h> //一些方便的函数
* 调用的一些关键函数部分:
普通版:
pthread_join() 等待线程的结束
pthread_create() 线程的创建
open() 打开文件,返回一个文件描述符,还可以声明一些权限部分
read() 通过文件描述符进行读
write() 通过文件描述符进行写
lseek() 进行文件读写位置的偏移
truncate() 进行文件的截断,即将目标文件变成与源文件大小相等
缺点:在多线程的运行过程中,会有一些IO错误冲突的情况,要注意避免。
解决方案:使用pread()、pwrite()
以上两个函数操作具有原子性,使得线程间互不干扰,而且不用lseek进行位置的偏移
评价:pread/pwrite性能优于read/write+lseek。并且具有原子性。强烈推荐
注意:不要和read/write/lseek混用
* 使用的数据结构
(在多线程中传递参数必须使用一个结构体作为参数列表传递数据):
/* * * 存放传输的信息 * * */
typedef struct file_info
{
char *src; //存储源文件的名字
char *obj; //存储目标文件的名字
off_t offset; //文件读写的偏移量
off_t size; //数据的大小
}F_INFO;
- 宏定义
/* * * 表示所创建的子线程总数 * * */
#define THREAD_COUNT (5)
- 多线程函数(用于让创建的线程执行的函数):
void *copy_thread(void *arg)
{
int src_fd,obj_fd; //文件描述符
F_INFO *fi = (F_INFO *)arg; //参数指针
char buffer[1024]; //临时存储的文件内容
int rd_size; //当前线程——真实读取的大小
int cnt=0; //当前线程——总共读取的数量
src_fd=open(fi->src,O_RDONLY); //只读权限
if(-1==src_fd)
{
perror("src is error!\n");
return ;
}
obj_fd=open(fi->obj,O_RDWR|O_CREAT);//后面的参数是读写权限+如果没有则创建obj文件
if(-1==obj_fd)
{
perror("obj is error!\n");
return ;
}
while(cnt<fi->size)
{
off_t size;
//所要读取的数据的大小
size=((sizeof(buffer)+cnt)>=(dm->size))?(dm->size-cnt):(sizeof(buffer));
rd_size=pread(src_fd,buffer,size,dm->offset);
if(-1==rd_size)
{
perror("read error!\n");
return ;
}
pwrite(obj_fd,buffer,rd_size,dm->offset);
cnt+=rd_size;
}
close(src_fd);
close(obj_fd);
return ;
}
- 以下为主函数的部分
int main(int argc,char **argv)
{
char *src; //源文件名称
char *obj; //目标文件名称
int i;
off_t offset=0;
int rd_len;
pthread_t tid[THREAD_COUNT]; //线程编号
struct stat src_st; //读取源文件的文件状态
F_INFO fi[THREAD_COUNT]; //每个线程的参数列表
src=argv[1]; //读取第一个参数,作为源文件
stat(src,&src_st); //获取文件状态(大小等...)
obj=argv[2]; //读取第二个参数,作为目标文件
truncate(obj,src_st.st_size);
for(i=0;i<THREAD_COUNT;i++)
{
fi[i].src=src;
fi[i].obj=obj;
fi[i].offset=(src_st.st_size/THREAD_COUNT)*i;
fi[i].size=src_st.st_size/THREAD_COUNT +
((i==THREAD_COUNT-1)?(src_st.st_size%THREAD_COUNT):0);
pthread_create(&tid[i],NULL,copy_thread,(void *)&fi[i]);
}
for(i=0;i<THREAD_COUNT;i++)
{
pthread_join(tid[i],NULL);
}
return 0;
}
今天干货满满,感觉又变强了(^__^) 嘻嘻……
学会在markdown中插入整块代码。(没错,我就是来打广告的~)