我目前在设计一个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);
}为什么线程总是第一个区间段写入完好,其余线程都不执行读写操作?另外我想问,一个已经打开的文件,文件偏移量这个变量是不是相对所有线程是唯一的???是公共涉及的变量???也就是说在某一个线程中修改了,在其余线程也会随之做同样的修改?还请高手们多多讲解。

解决方案 »

  1.   

    很简单,就是在主线程循环的关键位置加一个sleep()函数,主要是主线程运行过快,子线程还没来得及创建,主线程传给子线程的参数就发生了覆盖或者主线程提前退出。
    不过这个问题确实 折腾了我很久,最后我是在 《Linux程序设计》这本书中的POSIX线程一章的最后一个源代码程序的解释中找到的一点启发,我开始怀疑我的程序是否也有类似的问题。由此,我尝试着调试得到了解决的方案。不过最近人事的那些家伙在搞什么“成本大清洗”了,估计我也呆不长了,虽然我很喜欢钻研代码技术,工作也很认真,但是生存是首要前提。本帖平均给分,感谢大家的积极回复。
      

  2.   

    主线程创建子线程的代码我没贴出来。其实该修改的地方恰恰是没贴出来的那段。
    就是
    Linux端
    for循环
    pthread_create()
    pthread_join()
    sleep()//就在此处因为缺少了主线程时间停留windows端
    for循环
    CreateThread()
    Sleep()//问题就在此处因为缺少了主线程时间停留循环外部紧接着
    WaitForMultipleObjects();