/****/多线程假死,麻烦各位高手帮忙

殇迪 2007-01-20 11:35:19
帮一个同学写个程序,他手中有大量文件的下载地址,
这些地址存放在一个access数据库中,想让我写个程序下载这些文档。
我打算先从数据库中读出这些地址到一个list控件中,
然后再开n个线程来下载,下载文档的时候用CInternetSession。
调试的时候我觉得写日志的方式太麻烦,
就定义了一个消息——下载线程每运行一步就把自己的当前的
状态通过该消息发送给父窗口,在调试的时候我发现程序
刚运行的时候很比较正常——所有线程都在运行,
但是越来越多的线程开始假死,直到最后所有线程都好像死掉了。
麻烦各位达人指点迷津
分数不够可以再开贴
...全文
651 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2007-02-12
  • 打赏
  • 举报
回复
CInternetSession 封装的不太好,我在用的时候也经常出些问题。
殇迪 2007-02-12
  • 打赏
  • 举报
回复
SendMessage
尘雨 2007-02-09
  • 打赏
  • 举报
回复
我是通过向UI发送一个自定义消息来获取一个链接的
-------------------------------------------------
PostMessage还是SendMessage?
pig_2000 2007-02-09
  • 打赏
  • 举报
回复
这种问题一般是多线程之间同步时发生死锁现象引起的,是否用了信号量等,看看是否加锁后没解锁
殇迪 2007-02-09
  • 打赏
  • 举报
回复
没有直接访问UI,
我是通过向UI发送一个自定义消息来获取一个链接的
尘雨 2007-02-08
  • 打赏
  • 举报
回复
只有进入关键代码段的线程才有权利访问这个listCtrl

为什么不放在一个CList或者vector里,listCtrl属于UI,也要响应UI的消息,从工作线程访问UI不是什么好事情,一定程度上会影响到处理UI的主消息循环
殇迪 2007-02-08
  • 打赏
  • 举报
回复
自己顶一把
殇迪 2007-02-08
  • 打赏
  • 举报
回复
我知道线程太多也没有好处——时间都花在线程的切换上了
但是我开的线程并不多啊

另外,我的程序并不频繁访问access数据库,
我先把要下载的链接都从access中读到一个listCtrl中,
各个线程从listCtrl中读取下载链接,
我设置了一个关键代码段
只有进入关键代码段的线程才有权利访问这个listCtrl
应该不会有同步的问题吧!

麻烦各位高手指点,分数不够可以另外开贴
linuxpgy 2007-01-23
  • 打赏
  • 举报
回复
消息太多了吧?把消息关掉试试?
vcnewer 2007-01-22
  • 打赏
  • 举报
回复
到底开了多少线程啊,太多的话CPU 时间都用在context 切换上了,当然就假死了!多线程有时是能提高点效率,但也不能太多,多了反而影响效率!
yzcurry 2007-01-22
  • 打赏
  • 举报
回复
开的多了,控制一下,不管谁的机器,要是吃内存大或cpu利用率高都会假死的,你自己再分析一下
jhzhao2002 2007-01-22
  • 打赏
  • 举报
回复
先确定是访问数据库死掉还是CInternetSession东西死掉。
不要用CInternetSession下载。可以使用URLDownloadToFile系统api直接下载文件。
最好不要启太多的线程,只能让性能下降。
jhzhao2002 2007-01-22
  • 打赏
  • 举报
回复
把你要下的东西都下到文本文件里,然后用网际快车什么的下就行了呗。
microyzy 2007-01-22
  • 打赏
  • 举报
回复
可能性太多了,呵呵

除了以上各位分析的多线程本身的问题外,文件数量大,但是每个文件不大,这样会造成各个线程频繁读取access数据库,由于access数据库多用户性能很差,看看会不会试这个问题?
殇迪 2007-01-21
  • 打赏
  • 举报
回复
masterz(www.fruitfruit.com):
CInternetSession不能开的太多。少开几个thread
------------------
难道CInternetSession还有开线程不能太多这个“功能”^_^ !

我测试的时候开的线程分别为20个、10个、4个
2个都死了!!
1个的时候等的时间太长,没测试完……
==================
DentistryDoctor(不在无聊中无奈,就在沉默中变态) :
多线程的程序(死锁, 活锁)同步是个难题, 调试也是需要技巧的。

可以看《Windows核心编程》,《Win32多线程程序设计》
----------------------------------------
我的线程同步应该没什么问题——因为我的各个线程除了获取下载地址的时候需要同步
其他的资源都不需要同步
而获取下载地址的时候我用了关键代码段同步的,应该没问题!

==============================
yjgx007(还不结帖?!听妈妈的话! http://www.geekclaw.com):
开一个线程就足够了,我很早写的代码,你看下关键的就可了
----------------
一个线程太慢了,因为要下载的文件太多(但每个都不大)
——比如下载100个文件10个线程很快就搞定
1个线程要跑好长时间
DentistryDoctor 2007-01-20
  • 打赏
  • 举报
回复
多线程的程序(死锁, 活锁)同步是个难题, 调试也是需要技巧的。

可以看《Windows核心编程》,《Win32多线程程序设计》
yjgx007 2007-01-20
  • 打赏
  • 举报
回复
开一个线程就足够了,我很早写的代码,你看下关键的就可了

UINT CDownloadDlg::DownloadProc(LPVOID pVoid)
{
CDownloadDlg* pDlg = (CDownloadDlg*)pVoid;
s_isStop = false;
s_isFinish = false;

// Attemps to open internet connection
if (ERROR_SUCCESS != InternetAttemptConnect(0))
{
AfxMessageBox(_T("Can't find useful connection!\n"));
return 0;
}

HINTERNET hInternet = InternetOpen(_T("IE"),
PRE_CONFIG_INTERNET_ACCESS,
NULL,
INTERNET_INVALID_PORT_NUMBER,
0);
if (hInternet == NULL)
{
AfxMessageBox(_T("Failed to open internet connection!\n"));
return 0;
}

COleDateTime dtStart(COleDateTime::GetCurrentTime());
int nFilesCount = pDlg->m_arrMusicRecords.GetSize();
pDlg->m_downProgress.SetRange32(0, nFilesCount);

for (int i = 0; i < nFilesCount; ++i)
{
if (s_isStop == true)
break;

MusicRecord* pRec = pDlg->m_arrMusicRecords.GetAt(i);
if (pRec == NULL)
{
pDlg->m_downProgress.SetPos(i+1);

CString strCount;
strCount.Format(_T("%d"), i+1);
pDlg->m_ctlDownCount.SetWindowText(strCount);
COleDateTime dtCurrent(COleDateTime::GetCurrentTime());
CString timeSpan = (dtCurrent-dtStart).Format(_T("%H:%M:%S"));
pDlg->m_ctlElapseTime.SetWindowText(timeSpan);
continue;
}

DWORD dwContext = 0;
HINTERNET hUrlFile = InternetOpenUrl(
hInternet,
pRec->m_strUrl,
NULL,
0,
INTERNET_FLAG_RELOAD,
dwContext);
if (hUrlFile != NULL)
{
// Create new file to save downloading data
WIN32_FIND_DATA wfd = {0};
CString strSaveRootDir;
strSaveRootDir = pDlg->m_strSaveFolder + pRec->m_typeId;
HANDLE hFind = ::FindFirstFile(strSaveRootDir, &wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
::CreateDirectory(strSaveRootDir, NULL);
}
else
{
::FindClose(hFind);
}
CString strSaveDir = strSaveRootDir + _T("\\") + pRec->m_strSingerName;
hFind = ::FindFirstFile(strSaveDir, &wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
::CreateDirectory(strSaveDir, NULL);
}
else
{
::FindClose(hFind);
}

CString strExtName = _T("mp3");
int nPos = pRec->m_strUrl.ReverseFind('.');
if (nPos != -1)
strExtName = pRec->m_strUrl.Mid(nPos+1);

CString strSaveFilePath = strSaveDir + _T("\\") + pRec->m_strSongName + _T(".") + strExtName;
pDlg->m_ctlDownFileName.SetWindowText(strSaveFilePath);
CFile file;
if (!file.Open(strSaveFilePath, CFile::modeCreate|CFile::modeWrite))
{
// Error occur!
pDlg->m_arrErrRecords.Add(pRec);
pDlg->m_downProgress.SetPos(i+1);
continue;
}

char buffer[10*1024] ;
DWORD dwBytesRead = 0;
DWORD dwTotalBytes = 0;
SYSTEMTIME stStart;
::GetSystemTime(&stStart);
while (::InternetReadFile(hUrlFile,
buffer,
sizeof(buffer),
&dwBytesRead) && dwBytesRead != 0)
{
if (s_isStop == true)
break;
file.Write(buffer, dwBytesRead);

dwTotalBytes += dwBytesRead;

CString strCount;
strCount.Format(_T("%d"), i+1);
pDlg->m_ctlDownCount.SetWindowText(strCount);
COleDateTime dtCurrent(COleDateTime::GetCurrentTime());
CString timeSpan = (dtCurrent-dtStart).Format(_T("%H:%M:%S"));
pDlg->m_ctlElapseTime.SetWindowText(timeSpan);
}
SYSTEMTIME stCur;
::GetSystemTime(&stCur);
double speed = dwTotalBytes / (stCur.wMilliseconds - stStart.wMilliseconds);
CString strTotalBytes;
strTotalBytes.Format(_T("%f kb/s"), speed);
pDlg->m_ctlDownSpeed.SetWindowText(strTotalBytes);

::InternetCloseHandle(hUrlFile) ;
file.Close();
}
else
{
// Error occur!
pDlg->m_arrErrRecords.Add(pRec);
}

CString strCount;
strCount.Format(_T("%d"), i+1);
pDlg->m_ctlDownCount.SetWindowText(strCount);
COleDateTime dtCurrent(COleDateTime::GetCurrentTime());
CString timeSpan = (dtCurrent-dtStart).Format(_T("%H:%M:%S"));
pDlg->m_ctlElapseTime.SetWindowText(timeSpan);

pDlg->m_downProgress.SetPos(i+1);
}

::InternetCloseHandle(hInternet);

// Writes log file that will record all unsucceed records
if (pDlg->m_arrErrRecords.GetSize() > 0)
{
CString strErrorFile = pDlg->m_strSaveFolder + _T("error.log");
CStdioFile file;
if (file.Open(strErrorFile, CFile::modeCreate|CFile::modeWrite))
{
for (int i = 0; i < pDlg->m_arrErrRecords.GetSize(); ++i)
{
MusicRecord* pRec = pDlg->m_arrErrRecords.GetAt(i);
if (pRec == NULL)
continue;

CString strFormatText = pRec->m_strSingerName + _T(",") +
pRec->m_strSongName + _T(",") +
pRec->m_strUrl + _T(",") +
pRec->m_typeId + _T("\r\n");
file.WriteString(strFormatText);
}
}
file.Close();
}

s_isStop = true;
s_isFinish = true;

return 0;
}
masterz 2007-01-20
  • 打赏
  • 举报
回复
CInternetSession不能开的太多。少开几个thread

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧