今天闲来没事就写了个下面的程序。目的就是采用10个线程copy 同一文件的不同部位。然后写进同一文件。目的是实现了但结果却是不尽人意。
我没见过多线程的下载软件源码我也不了解他们的原理。
所以我又写了个简单的copy单线程直读直写。
测试了下 。复制一个680M的电影。所花的时间多线程(10个)是单线程的一倍……好慢……
为什么呢?
源码贴上吧。希望有人指教。
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#define MAXLINE 8192
#define SLEN 11
#define PATH "./"
#define NEW "new_"
/* 在同一目录下 如出现重名文件则加上 "new_" */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
typedef struct {
char * s_read;
char * s_writ;
pthread_t s_tid;
off_t s_seek;
size_t s_bytes;
}s_pthread;
/*
为了避免加锁 我为每个线程结构保存读,写文件的路径,在各自线程内在打开
这样就为每个线程创建了一个file。又因为写的操作在不同部位,所以避免了
各进程的竞争。不使用任何互斥量。估计很大原因就慢在这里了。
s_seek 每个线程的偏移量。
s_bytes 每线程所必读的字节数。
*/
static void err_msg(char *);
static void err_bmsg(char *);
static void init_pthread_file(s_pthread * , off_t , char* , char* );
static void* do_pthread(void *);
static ulong gettime(struct timeval *, struct timeval *);
static void do_no_pthread(int , int);
static char* getfilename(char *);
int
main(int argc, char **argv)
{
struct stat statbuf;
s_pthread sq[SLEN];
char path[128], *mssg;
int rfd, wfd, i;
struct timeval in, out;
if(argc < 2)
err_msg("no find of cp file……");
setbuf(stdout, NULL);
rfd = open(argv[1], O_RDONLY);
if(rfd < 0)
err_msg("open error");
if(fstat(rfd, &statbuf) < 0)
err_msg("read file size error");
sprintf(path, "%s%s", PATH, getfilename(argv[1]));
/*
getfilename( 1 ) 取文件名 如 /home/shana/xx.xx 取出 xx.xx
*/
if(open(path, O_RDONLY) > 0) { /*以打开方式查看 是否存在, 想不到别的方法来查看了*/
char mnt[128];
sprintf(mnt, "%s%s%s", PATH, NEW, path+2); /*path 包含了 "./" 2个字符 */
strcpy(path, mnt);
wfd = open(mnt, O_TRUNC | O_CREAT | O_RDWR, FILE_MODE);
if(wfd < 0)
err_msg("creat 1 new file error");
} else {
wfd = open(path, O_TRUNC | O_CREAT | O_RDWR, FILE_MODE);
if(wfd < 0)
err_msg("creat 2 new file error");
}
init_pthread_file(sq, statbuf.st_size, path, argv[1]);
/*
初始化线程结构
*/
if(argv[2] != NULL) {
if(atoi(argv[2]) == 2) {
gettimeofday(&in, NULL);
do_no_pthread(rfd, wfd); /*如果第三个参数不为空 且为 2 就使用 单线程cpoy */
gettimeofday(&out, NULL);
goto out;
}
}
gettimeofday(&in, NULL);
for(i = 0; i < SLEN; ++i)
pthread_create(&sq[i].s_tid, NULL, &do_pthread, &sq[i]);
for(i = 0; i < SLEN; ++i) {
pthread_join(sq[i].s_tid, (void*)&mssg);
printf("pthread : No.%d : %s/n", i, mssg);
}
gettimeofday(&out, NULL);
out:
printf("have time = %u ms/n", gettime(&out, &in));
close(rfd);
close(wfd);
return (0);
}
static void
err_msg(char * err)
{
printf("%s/n", err);
exit(-1);
}
static void
err_bmsg(char *err)
{
printf("%s/n", err);
}
/*
线程初始化 copy文件总长度 除以10 然后保留 余数。
每个线程copy十分之一
如余数不为0 则必须在打开一个线程copy 余数
*/
static void
init_pthread_file(s_pthread *qp , off_t len, char *wfd, char *rfd)
{
int i;
size_t bytes = len / (SLEN - 1);
size_t modby = len % (SLEN - 1);
bzero(qp, sizeof(s_pthread) * SLEN);
if(modby == 0) {
for(i = 0; i < ( SLEN - 1 ); ++i, qp++) {
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = i * bytes;
qp->s_bytes = bytes;
}
}
else {
for(i = 0; i < (SLEN - 1); ++i, qp++) {
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = i * bytes;
qp->s_bytes = bytes;
}
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = (i++) * bytes;
qp->s_bytes = modby;
}
}
/*
线程copy 函数 每个线程打开读写文件
设置偏移量,进行读写操作
*/
static void*
do_pthread(void *datae)
{
s_pthread *qp = (s_pthread *)datae;
off_t leek;
int read_d, writ_d;
size_t rbyte, rm = 0;
char data[MAXLINE];
if(qp->s_bytes == 0)
return (NULL);
read_d = open(qp->s_read, O_RDONLY);
writ_d = open(qp->s_writ, O_WRONLY, FILE_MODE);
if(read_d < 0 || writ_d < 0)
pthread_exit("pthread open error");
if(lseek(read_d, qp->s_seek, SEEK_SET) == -1)
pthread_exit("pthread read lseek error");
if(lseek(writ_d, qp->s_seek, SEEK_SET) == -1)
pthread_exit("pthread writ lseek error");
while( rm < qp->s_bytes ) {
rbyte = read(read_d, data, MAXLINE);
if(rbyte < 0)
pthread_exit("read error");
if( write(writ_d, data, rbyte) != rbyte)
pthread_exit("write error");
rm += rbyte;
}
close(read_d);
close(writ_d);
pthread_exit("ok");
}
static ulong
gettime(struct timeval *out, struct timeval *in)
{
return ((out->tv_sec - in->tv_sec)*1000000 + (out->tv_usec-in->tv_usec));
}
/*
单线程读写
*/
static void
do_no_pthread(int rfd, int wfd)
{
char data[MAXLINE];
size_t rbyte;
lseek(wfd, 0, SEEK_SET);
no_pthread_agin:
while( (rbyte = read(rfd, data, MAXLINE) ) > 0) {
if( write(wfd, data, rbyte) != rbyte)
err_msg("no pthread write");
}
if(rbyte < 0)
if(errno == EINTR)
goto no_pthread_agin;
}
static char*
getfilename(char *path)
{
char *top;
int len;
len = strlen(path);
top = path + len;
while(*top-- != '/') len--;
if(len == 0) return (top);
return (top + 2);
}
我没见过多线程的下载软件源码我也不了解他们的原理。
所以我又写了个简单的copy单线程直读直写。
测试了下 。复制一个680M的电影。所花的时间多线程(10个)是单线程的一倍……好慢……
为什么呢?
源码贴上吧。希望有人指教。
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#define MAXLINE 8192
#define SLEN 11
#define PATH "./"
#define NEW "new_"
/* 在同一目录下 如出现重名文件则加上 "new_" */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
typedef struct {
char * s_read;
char * s_writ;
pthread_t s_tid;
off_t s_seek;
size_t s_bytes;
}s_pthread;
/*
为了避免加锁 我为每个线程结构保存读,写文件的路径,在各自线程内在打开
这样就为每个线程创建了一个file。又因为写的操作在不同部位,所以避免了
各进程的竞争。不使用任何互斥量。估计很大原因就慢在这里了。
s_seek 每个线程的偏移量。
s_bytes 每线程所必读的字节数。
*/
static void err_msg(char *);
static void err_bmsg(char *);
static void init_pthread_file(s_pthread * , off_t , char* , char* );
static void* do_pthread(void *);
static ulong gettime(struct timeval *, struct timeval *);
static void do_no_pthread(int , int);
static char* getfilename(char *);
int
main(int argc, char **argv)
{
struct stat statbuf;
s_pthread sq[SLEN];
char path[128], *mssg;
int rfd, wfd, i;
struct timeval in, out;
if(argc < 2)
err_msg("no find of cp file……");
setbuf(stdout, NULL);
rfd = open(argv[1], O_RDONLY);
if(rfd < 0)
err_msg("open error");
if(fstat(rfd, &statbuf) < 0)
err_msg("read file size error");
sprintf(path, "%s%s", PATH, getfilename(argv[1]));
/*
getfilename( 1 ) 取文件名 如 /home/shana/xx.xx 取出 xx.xx
*/
if(open(path, O_RDONLY) > 0) { /*以打开方式查看 是否存在, 想不到别的方法来查看了*/
char mnt[128];
sprintf(mnt, "%s%s%s", PATH, NEW, path+2); /*path 包含了 "./" 2个字符 */
strcpy(path, mnt);
wfd = open(mnt, O_TRUNC | O_CREAT | O_RDWR, FILE_MODE);
if(wfd < 0)
err_msg("creat 1 new file error");
} else {
wfd = open(path, O_TRUNC | O_CREAT | O_RDWR, FILE_MODE);
if(wfd < 0)
err_msg("creat 2 new file error");
}
init_pthread_file(sq, statbuf.st_size, path, argv[1]);
/*
初始化线程结构
*/
if(argv[2] != NULL) {
if(atoi(argv[2]) == 2) {
gettimeofday(&in, NULL);
do_no_pthread(rfd, wfd); /*如果第三个参数不为空 且为 2 就使用 单线程cpoy */
gettimeofday(&out, NULL);
goto out;
}
}
gettimeofday(&in, NULL);
for(i = 0; i < SLEN; ++i)
pthread_create(&sq[i].s_tid, NULL, &do_pthread, &sq[i]);
for(i = 0; i < SLEN; ++i) {
pthread_join(sq[i].s_tid, (void*)&mssg);
printf("pthread : No.%d : %s/n", i, mssg);
}
gettimeofday(&out, NULL);
out:
printf("have time = %u ms/n", gettime(&out, &in));
close(rfd);
close(wfd);
return (0);
}
static void
err_msg(char * err)
{
printf("%s/n", err);
exit(-1);
}
static void
err_bmsg(char *err)
{
printf("%s/n", err);
}
/*
线程初始化 copy文件总长度 除以10 然后保留 余数。
每个线程copy十分之一
如余数不为0 则必须在打开一个线程copy 余数
*/
static void
init_pthread_file(s_pthread *qp , off_t len, char *wfd, char *rfd)
{
int i;
size_t bytes = len / (SLEN - 1);
size_t modby = len % (SLEN - 1);
bzero(qp, sizeof(s_pthread) * SLEN);
if(modby == 0) {
for(i = 0; i < ( SLEN - 1 ); ++i, qp++) {
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = i * bytes;
qp->s_bytes = bytes;
}
}
else {
for(i = 0; i < (SLEN - 1); ++i, qp++) {
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = i * bytes;
qp->s_bytes = bytes;
}
qp->s_read = rfd;
qp->s_writ = wfd;
qp->s_seek = (i++) * bytes;
qp->s_bytes = modby;
}
}
/*
线程copy 函数 每个线程打开读写文件
设置偏移量,进行读写操作
*/
static void*
do_pthread(void *datae)
{
s_pthread *qp = (s_pthread *)datae;
off_t leek;
int read_d, writ_d;
size_t rbyte, rm = 0;
char data[MAXLINE];
if(qp->s_bytes == 0)
return (NULL);
read_d = open(qp->s_read, O_RDONLY);
writ_d = open(qp->s_writ, O_WRONLY, FILE_MODE);
if(read_d < 0 || writ_d < 0)
pthread_exit("pthread open error");
if(lseek(read_d, qp->s_seek, SEEK_SET) == -1)
pthread_exit("pthread read lseek error");
if(lseek(writ_d, qp->s_seek, SEEK_SET) == -1)
pthread_exit("pthread writ lseek error");
while( rm < qp->s_bytes ) {
rbyte = read(read_d, data, MAXLINE);
if(rbyte < 0)
pthread_exit("read error");
if( write(writ_d, data, rbyte) != rbyte)
pthread_exit("write error");
rm += rbyte;
}
close(read_d);
close(writ_d);
pthread_exit("ok");
}
static ulong
gettime(struct timeval *out, struct timeval *in)
{
return ((out->tv_sec - in->tv_sec)*1000000 + (out->tv_usec-in->tv_usec));
}
/*
单线程读写
*/
static void
do_no_pthread(int rfd, int wfd)
{
char data[MAXLINE];
size_t rbyte;
lseek(wfd, 0, SEEK_SET);
no_pthread_agin:
while( (rbyte = read(rfd, data, MAXLINE) ) > 0) {
if( write(wfd, data, rbyte) != rbyte)
err_msg("no pthread write");
}
if(rbyte < 0)
if(errno == EINTR)
goto no_pthread_agin;
}
static char*
getfilename(char *path)
{
char *top;
int len;
len = strlen(path);
top = path + len;
while(*top-- != '/') len--;
if(len == 0) return (top);
return (top + 2);
}