我目前在设计一个win32/Linux的跨平台通信程序。现在从Linux下载文件到win32平台下。
单线程的代码是成功的。但为了应对大文件和缩短下载时间,我打算采用多线程处理。
//多线程下载,客户端的写入操作
DWORD WINAPI WriteFileThread(LPVOID lparam)
{
PWDP pWdp=(PWDP)lparam;
UINT DataSize=0;
UINT BufSize=MAX_PATH;
BYTE *buff=new BYTE[BufSize];
memset(buff,0,BufSize);
char szDir[MAX_PATH]={0};
char szText[MAX_PATH]={0};
int recvlen=0;
long OffSet=0;
recvlen=recv(pWdp->s,szText,sizeof(szText),0);
if (SOCKET_ERROR==recvlen)
{
closesocket(pWdp->s);
return 0;//写入文件失败
}
DataSize=atoi(szText);
OffSet=DataSize*pWdp->index;
//设置块数据区间段起始位置为距离
//文件起始位置偏移
//OffSet个字符的位置
//LARGE_INTEGER Distance={0};
//Distance.QuadPart
SetFilePointer(pWdp->hFile,OffSet,0,FILE_BEGIN);
//_lseek((int)(pWdp->hFile),OffSet,SEEK_SET);
DWORD total;
UINT Capacity=0;
UINT Num=BufSize; while(Capacity<DataSize)
{
if (DataSize-Capacity<BufSize)
{
Num=DataSize-Capacity;
}
recvlen = recv(pWdp->s,(char*)buff,Num,0);
if (SOCKET_ERROR==recvlen)
{
closesocket(pWdp->s);
return 0;
}
Capacity += recvlen;
//注意有时网络有阻塞行为,不一定Num=recvlen
::WriteFile(pWdp->hFile,buff,recvlen,&total,NULL);
memset(buff,0,BufSize);
}
delete [] buff;
return 1;
}
Linux下的读取线程操作typedef struct ReadData_Parameter
{
int hFile;
DWORD DataSize;//DWORD我在Linux中进行了重定义使得它和windows下的意义一致
long OffSet;
int s;//端套接字描述符
}RDP,*PRDP;//hFile是待读取文件的文件描述符
//DataSize是多线程处理区间数据段的大小
//如果OffSet的值是0,DataSize是整个文件大小
//则该函数直接读取整个文件的数据信息
int ReadData(int hFile,
DWORD DataSize,
long OffSet,int s)
{//OffSet是long int 类型
UINT BufSize=MAX_PATH;
BYTE *buff=new BYTE[BufSize];
memset(buff,0,BufSize);
char szText[MAX_PATH]={0};
UINT i;
/*
DWORD FileSize;
FileSize=GetFileSizeEx(srcDir);//获取文件大小
*/
//转移文件偏移量至指定位置
lseek(hFile,OffSet,SEEK_SET);
sprintf(szText,"%ld",DataSize);//DataSize=FileSize/10 if (SOCKET_ERROR==send(s,szText,sizeof(szText),0))
{
close(hFile);
shutdown(s,SHUT_RDWR);
return 0;
}
UINT total=(UINT)(DataSize/BufSize);
UINT count=DataSize%BufSize==0?total:total+1; UINT Capacity=0;
UINT Num=BufSize;
for(i=0;i<count;++i)
{
if (DataSize-Capacity<BufSize)
{
Num=(UINT)(DataSize-Capacity);
}
read(hFile,buff,Num);
Capacity+=Num;
if (SOCKET_ERROR==send(s,(char*)buff,Num,0))
{
close(hFile);
shutdown(s,SHUT_RDWR);
return 0;
}
memset(buff,0,BufSize);//原来是Num
}
delete [] buff;
return 1;
}void* ReadDataThread(void* arg)
{
//读取文件某一区间段的的数据流
int Ret=0;
PRDP prdp=(PRDP)arg;
if(9==(prdp->OffSet)/(prdp->DataSize))
{
prdp->DataSize=prdp->DataSize*10-prdp->OffSet;
}
Ret=ReadData(prdp->hFile,
prdp->DataSize,
prdp->OffSet,
prdp->s);
pthread_exit((void*)Ret);
//sleep(1000);
}为什么线程总是第一个区间段写入完好,其余线程都不执行读写操作?另外我想问,一个已经打开的文件,文件偏移量这个变量是不是相对所有线程是唯一的???是公共涉及的变量???也就是说在某一个线程中修改了,在其余线程也会随之做同样的修改?还请高手们多多讲解。
单线程的代码是成功的。但为了应对大文件和缩短下载时间,我打算采用多线程处理。
//多线程下载,客户端的写入操作
DWORD WINAPI WriteFileThread(LPVOID lparam)
{
PWDP pWdp=(PWDP)lparam;
UINT DataSize=0;
UINT BufSize=MAX_PATH;
BYTE *buff=new BYTE[BufSize];
memset(buff,0,BufSize);
char szDir[MAX_PATH]={0};
char szText[MAX_PATH]={0};
int recvlen=0;
long OffSet=0;
recvlen=recv(pWdp->s,szText,sizeof(szText),0);
if (SOCKET_ERROR==recvlen)
{
closesocket(pWdp->s);
return 0;//写入文件失败
}
DataSize=atoi(szText);
OffSet=DataSize*pWdp->index;
//设置块数据区间段起始位置为距离
//文件起始位置偏移
//OffSet个字符的位置
//LARGE_INTEGER Distance={0};
//Distance.QuadPart
SetFilePointer(pWdp->hFile,OffSet,0,FILE_BEGIN);
//_lseek((int)(pWdp->hFile),OffSet,SEEK_SET);
DWORD total;
UINT Capacity=0;
UINT Num=BufSize; while(Capacity<DataSize)
{
if (DataSize-Capacity<BufSize)
{
Num=DataSize-Capacity;
}
recvlen = recv(pWdp->s,(char*)buff,Num,0);
if (SOCKET_ERROR==recvlen)
{
closesocket(pWdp->s);
return 0;
}
Capacity += recvlen;
//注意有时网络有阻塞行为,不一定Num=recvlen
::WriteFile(pWdp->hFile,buff,recvlen,&total,NULL);
memset(buff,0,BufSize);
}
delete [] buff;
return 1;
}
Linux下的读取线程操作typedef struct ReadData_Parameter
{
int hFile;
DWORD DataSize;//DWORD我在Linux中进行了重定义使得它和windows下的意义一致
long OffSet;
int s;//端套接字描述符
}RDP,*PRDP;//hFile是待读取文件的文件描述符
//DataSize是多线程处理区间数据段的大小
//如果OffSet的值是0,DataSize是整个文件大小
//则该函数直接读取整个文件的数据信息
int ReadData(int hFile,
DWORD DataSize,
long OffSet,int s)
{//OffSet是long int 类型
UINT BufSize=MAX_PATH;
BYTE *buff=new BYTE[BufSize];
memset(buff,0,BufSize);
char szText[MAX_PATH]={0};
UINT i;
/*
DWORD FileSize;
FileSize=GetFileSizeEx(srcDir);//获取文件大小
*/
//转移文件偏移量至指定位置
lseek(hFile,OffSet,SEEK_SET);
sprintf(szText,"%ld",DataSize);//DataSize=FileSize/10 if (SOCKET_ERROR==send(s,szText,sizeof(szText),0))
{
close(hFile);
shutdown(s,SHUT_RDWR);
return 0;
}
UINT total=(UINT)(DataSize/BufSize);
UINT count=DataSize%BufSize==0?total:total+1; UINT Capacity=0;
UINT Num=BufSize;
for(i=0;i<count;++i)
{
if (DataSize-Capacity<BufSize)
{
Num=(UINT)(DataSize-Capacity);
}
read(hFile,buff,Num);
Capacity+=Num;
if (SOCKET_ERROR==send(s,(char*)buff,Num,0))
{
close(hFile);
shutdown(s,SHUT_RDWR);
return 0;
}
memset(buff,0,BufSize);//原来是Num
}
delete [] buff;
return 1;
}void* ReadDataThread(void* arg)
{
//读取文件某一区间段的的数据流
int Ret=0;
PRDP prdp=(PRDP)arg;
if(9==(prdp->OffSet)/(prdp->DataSize))
{
prdp->DataSize=prdp->DataSize*10-prdp->OffSet;
}
Ret=ReadData(prdp->hFile,
prdp->DataSize,
prdp->OffSet,
prdp->s);
pthread_exit((void*)Ret);
//sleep(1000);
}为什么线程总是第一个区间段写入完好,其余线程都不执行读写操作?另外我想问,一个已经打开的文件,文件偏移量这个变量是不是相对所有线程是唯一的???是公共涉及的变量???也就是说在某一个线程中修改了,在其余线程也会随之做同样的修改?还请高手们多多讲解。
解决方案 »
- 怎么把一个CArray对象的值赋给另一个CArray对象?
- 如何响应窗口移动事件
- 求助:VC当文档中添加了一个控件,如何给这个控件关联一个变量。
- ON_UPDATE_COMMAND_UI 只能在CMainFrame才能改变菜单状态>?
- 在自己做的界面里显示网页后,如何在界面中增加“刷新,回到首页,后退,向前”功能?
- 如何在VC2005中让ComoBox的下拉框一次显示全部的内容
- 鼠标形状的怪问题
- 请教:如何用分形算法实现BMP图像的任意比例的高质量缩放?
- 请问:在mfc中用combobox有CComboBox::GetCurSel(),在sdk中怎么得到所选项
- 又来麻烦大家了,很急的udp连接的问题,100分送上。
- Windows Explorer扩展编程
- CSocket ReceiveFrom奇怪错误,大家看看
不过这个问题确实 折腾了我很久,最后我是在 《Linux程序设计》这本书中的POSIX线程一章的最后一个源代码程序的解释中找到的一点启发,我开始怀疑我的程序是否也有类似的问题。由此,我尝试着调试得到了解决的方案。不过最近人事的那些家伙在搞什么“成本大清洗”了,估计我也呆不长了,虽然我很喜欢钻研代码技术,工作也很认真,但是生存是首要前提。本帖平均给分,感谢大家的积极回复。
就是
Linux端
for循环
pthread_create()
pthread_join()
sleep()//就在此处因为缺少了主线程时间停留windows端
for循环
CreateThread()
Sleep()//问题就在此处因为缺少了主线程时间停留循环外部紧接着
WaitForMultipleObjects();