多线程拷贝命令的实现,如:./my_cp src_file dest_file N(拷贝线程个数)
思路:先把src_file用mmap映射到内存里面,私人模式,然后创建dest_file,文件大小于src一样,也映射到内存空间去,然后把根据线程个数,把文件分割.
定义一个结构体,元素有每个线程要拷贝的起始指针位置,块大小,以及这是第几个线程.
定义一个全局整形数组指针,指向一个动态数组空间,数组的大小和线程的个数一致,用于进度条.
代码的实现:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
int *array;
void sys_err(const char *str)
{
perror(str);
exit(0);
}
struct cp {
char *srcm_add;
char *destm_add;
int thread_num;
int block_size;
};
void *thread_cpy(void *arg)
{
struct cp *im = (struct cp *)arg;
int block = im->block_size;
char *srcm_add = im->srcm_add;
char *destm_add = im->destm_add;
while(block--) { //One byte of a byte copy
*destm_add++ = *srcm_add++;
array[im->thread_num]++;
usleep(1000);
}
free(im);
}
int main(int argc, char *argv[])
{
int fdsrc, fddest;
int src_size = 0;
char *srcm_add, *destm_add;
int block_size;
int thread_num;
pthread_t tid;
struct cp *im;
int i;
int err;
int sum = 0;
pthread_attr_t attr;
struct stat st;
if (argc < 3) {
printf("./a.out srcfile destfile\n");
exit(1);
}
/* open fdsrc ,get fdsrc size*/
if((fdsrc = open(argv[1], O_RDONLY)) < 0)
sys_err("open src");
if((src_size = lseek(fdsrc, 0, SEEK_END)) < 0)
sys_err("lseek fdsrc");
if(stat(argv[1], &st))
sys_err("stat");
st.st_mode &= 0777;
/* create fddest, mode and size*/
if((fddest = open(argv[2], O_CREAT|O_RDWR, st.st_mode)) < 0)
sys_err("open dest");
if(lseek(fddest, src_size-1, SEEK_SET) < 0)
sys_err("lseek dest");
if(write(fddest, "\0", 1) < 0)
sys_err("write creat dest");
/* block number*/
if(argc == 3)
thread_num = 5;
else
thread_num = atoi(argv[3]);
/* chick num */
array = calloc(sizeof(int), thread_num);
/* copy file to mmap */
srcm_add = mmap(NULL, src_size, PROT_READ, MAP_PRIVATE, fdsrc, 0);
destm_add = mmap(NULL,src_size, PROT_WRITE, MAP_SHARED, fddest, 0);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/* create thread */
for (i=0; i<thread_num; i++) {
if(i == (thread_num-1))
block_size = src_size/thread_num + src_size%thread_num;
else
block_size = src_size/thread_num;
im = calloc(sizeof(struct cp), 1);
im->srcm_add = srcm_add + i * (src_size/thread_num);
im->destm_add = destm_add + i * (src_size/thread_num);
im->block_size = block_size;
im->thread_num = i;
err = pthread_create(&tid, &attr, thread_cpy, (void *)im);
if(err != 0)
fprintf(stderr, "%s\n", strerror(err));
}
int j, k = 1;
j = src_size/20;
do {
sum = 0;
for (i=0; i<thread_num; i++)
sum += array[i];
if(sum > j*k) {
k++;
write(STDOUT_FILENO, "==", 2);
}
usleep(10000);
} while(sum < src_size);
printf("\n");
free(array);
munmap(srcm_add, src_size);
munmap(destm_add, src_size);
return 0;
}
注意:如果要映射的文件过大,不能一下子全部映射内存里面,要一部分一部分的映射到内存里面,然后在一点一点往另一个内存拷贝,但还要注意,mmap的最小偏移量4096。
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
int *array;
void sys_err(const char *str)
{
perror(str);
exit(0);
}
struct cp {
char *srcm_add;
char *destm_add;
int thread_num;
int block_size;
};
void *thread_cpy(void *arg)
{
struct cp *im = (struct cp *)arg;
int block = im->block_size;
char *srcm_add = im->srcm_add;
char *destm_add = im->destm_add;
while(block--) { //One byte of a byte copy
*destm_add++ = *srcm_add++;
array[im->thread_num]++;
usleep(100);
}
free(im);
}
int main(int argc, char *argv[])
{
int fdsrc, fddest;
int src_size = 0;
char *srcm_add, *destm_add;
int block_size;
int thread_num;
pthread_t tid;
struct cp *im;
int i;
int err;
int sum = 0;
pthread_attr_t attr;
struct stat st;
int page_size;
int page_num;
int page_count = 0;
if (argc < 3) {
printf("./a.out srcfile destfile\n");
exit(1);
}
/* open fdsrc ,get fdsrc size*/
if((fdsrc = open(argv[1], O_RDONLY)) < 0)
sys_err("open src");
if((src_size = lseek(fdsrc, 0, SEEK_END)) < 0)
sys_err("lseek fdsrc");
if(stat(argv[1], &st))
sys_err("stat");
st.st_mode &= 0777;
/* create fddest, and set size*/
if((fddest = open(argv[2], O_CREAT|O_RDWR, st.st_mode)) < 0)
sys_err("open dest");
if(lseek(fddest, src_size-1, SEEK_SET) < 0)
sys_err("lseek dest");
if(write(fddest, "\0", 1) < 0)
sys_err("write creat dest");
if(argc == 3)
thread_num = 5;
else
thread_num = atoi(argv[3]);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(src_size > 4096) {
page_num = src_size/4096 + 1;
for(page_count=0; page_count<page_num; page_count++) {
array = calloc(sizeof(int), thread_num);
if(page_count == (page_num-1))
page_size = src_size%4096;
else
page_size = 4096;
srcm_add = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, fdsrc, 4096*page_count);
destm_add = mmap(NULL,page_size, PROT_WRITE, MAP_SHARED, fddest, 4096*page_count);
for (i=0; i<thread_num; i++) {
if(i == (thread_num-1))
block_size = page_size/thread_num + page_size%thread_num;
else
block_size = page_size/thread_num;
im = calloc(sizeof(struct cp), 1);
im->srcm_add = srcm_add + i * (page_size/thread_num);
im->destm_add = destm_add + i * (page_size/thread_num);
im->block_size = block_size;
im->thread_num = i;
err = pthread_create(&tid, &attr, thread_cpy, (void *)im);
if(err != 0)
fprintf(stderr, "%s\n", strerror(err));
}
int j, k = 1;
j = page_size/20;
do {
sum = 0;
for (i=0; i<thread_num; i++)
sum += array[i];
if(sum > j*k) {
k++;
write(STDOUT_FILENO, "==", 2);
}
usleep(10000);
} while(sum < page_size);
printf("\n");
free(array);
munmap(srcm_add, page_size);
munmap(destm_add, page_size);
}
}
return 0;
}