当前位置:编程学习 > VC++ >>

WinInet多线程下载器编写历程(1)

昨天第一天开始编写使用Win32 API :WinInet 的多线程下载器,作为毕业设计,我准备把开发的过程记录下来。
 
总结一下昨天遇到的问题吧:
 
 
(1)架构
 
我初步架构了一下:
 
1.每个下载任务,即一个CDingDownload的对象,对象成员包括此下载任务的各种配置信息:
 
源URL,目标文件名,线程数,块大小,Owner窗口句柄(发通知消息用)
 
2.CDingDownload中有一个主控线程,控制多线程下载
 
问题出现了: 线程的过程函数必须是类中的static函数,但是static是没有this指针的,只能访问静态变量
 
为了解决这个问题,我将this指针放在主控线程 过程函数的参数结构体里面,这样static线程也能区分不同的对象了,可以通过指针访问对象成员
 
 
struct MainControlParam 

    CDingHttpDownload * p_this; 
}; 
 
VOID CDingHttpDownload::Start() 

m_state = running; 
m_mainctlparam.p_this = this; 
m_thread_maincontrol = CreateThread(NULL,0,MainControlProc,&m_mainctlparam,0,NULL); 

 
 
DWORD WINAPI CDingHttpDownload::MainControlProc(LPVOID lpParam) 

    MainControlParam *pParam = (MainControlParam *)lpParam; 
    CDingHttpDownload *pthis = pParam->p_this;               //对象指针 
    HWND hwnd = pthis->m_hwnd;                               //主窗口句柄 
    PTCHAR URL = pthis->m_URL; 

 
 
3.主控线程获取文件信息,开始分发任务下载(创建下载线程),并发送自定义消息通知窗口
 
 
关于自定义消息的使用:
 
首先定义消息,自定义消息都是从WM_USER往上的
 
 
#define WM_USER_THREAD_REQUEST (WM_USER + 0x101) 
 
然后声明定义回调函数
 
afx_msg LRESULT OnThreadRequest(WPARAM wparam,LPARAM lparam); 
 
LRESULT CDownloaderDlg::OnThreadRequest(WPARAM wparam,LPARAM lparam) 

return 0; 

 
最后加入消息映射
 
BEGIN_MESSAGE_MAP(CDownloaderDlg, CDialogEx) 
    ON_WM_SYSCOMMAND() 
    ON_WM_PAINT() 
    ON_WM_QUERYDRAGICON() 
    ON_BN_CLICKED(IDC_BUTTON1, &CDownloaderDlg::OnBnClickedButton1) 
    ON_MESSAGE(WM_USER_THREAD_REQUEST,OnThreadRequest) 
END_MESSAGE_MAP() 
 
 
 
4.主控线程维护一个信号量来控制线程数,开始不断创建任务
 
 
 
semaphore_threads = CreateSemaphore(NULL,pthis->m_threadnum,pthis->m_threadnum,NULL); 
 
while循环,www.zzzyk.com获取信号量后创建下载线程
 
 
while (pthis->m_state == running) 

    WaitForSingleObject(semaphore_threads,INFINITE); 
 
    DownloadThreadParam *param = new DownloadThreadParam(); 
    param->p_this = pthis; 
    param->mutex_progress = mutex_progress; 
    param->semaphore_threads = semaphore_threads; 
    param->range1 = 0; 
    param->range2 = 1024; 
    CreateThread(NULL,0,DownloadProc,param,0,NULL); 

 
下载线程下载完成自己的任务块之后释放信号量:
 
DownloadProc尾部:
 
ReleaseSemaphore(pParm->semaphore_threads,1,NULL); 
 
 
(2)遇到的问题
 
1.内存分配的问题:
 
DownloaderDlg.cpp中的按钮响应函数中构造一个下载类:
注意我注释掉的部分使用new来申请一个buffer然后传递给下载类的构造函数
 
 
//PTCHAR URL = new TCHAR(50); 
PTCHAR URL = (PTCHAR)GlobalAlloc(0,50*sizeof(TCHAR)); 
_tcscpy(URL,_T("127.0.0.1")); 
//PTCHAR filename = new TCHAR(50); 
PTCHAR filename = (PTCHAR)GlobalAlloc(0,50*sizeof(TCHAR)); 
_tcscpy(filename,_T("ding.down.php")); 
 
m_pdownload = new CDingHttpDownload(this->m_hWnd,URL,filename); 
 
httpcore.cpp构造函数部分:
 
CDingHttpDownload::CDingHttpDownload(HWND handle,PTCHAR URL,PTCHAR filename,\ 
        UINT threadnum,UINT blocksize,UINT cache)\ 
    :m_hwnd(handle),m_threadnum(threadnum),m_blocksize(blocksize),m_cache(cache) 

 
    //m_URL = new TCHAR(50); 
    m_URL = (PTCHAR)GlobalAlloc(0,(_tcslen(URL)+1)*sizeof(TCHAR)); 
    _tcscpy(m_URL,URL); 
    //m_filename = new TCHAR(50); 
    m_filename = (PTCHAR)GlobalAlloc(0,(_tcslen(filename)+1)*sizeof(TCHAR)); 
    _tcscpy(m_filename,filename); 

 
如果我使用注释掉的new方式来申请内存,会在运行过程中遇到错误,并提示"其原因可能是堆被损坏,这也说明程序中或它所加载的任何DLL 中有bug"
如果改成GlobalAlloc就没问题了,可是我的程序并没有使用DLL啊,应该还是一个堆呀?
 
难道是MFC和这段代码用的是不同的堆吗?
 
注:我使用的是静态链接MFC库的方式。
 
刚才调试了一下,发现在httpcore.cpp,构造函数里面new的地址和在DownloaderDlg.cpp中new地址相差很大。

摘自 New Day New Plan 。
补充:软件开发 , Vc ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,