接上贴,线程访问全局变量有异常,高手接续帮忙解决一下

edisonli 2008-07-27 04:29:42
UINT CUpdateDlg::DownloadThread(void *pArg)
{
CUpdateDlg *pMainWnd = (CUpdateDlg *)pArg;
CHttpSocket HttpSocket;
CString strServer,strObject;
unsigned short nPort;
DWORD dwServiceType;
long nLength;
const char *pRequestHeader = NULL;
//CString xxx;
//xxx.Format("%d",pMainWnd->m_list.GetItemCount());
//AfxMessageBox(xxx);
for (int i=1;i <=pMainWnd->m_list.GetItemCount();i++){
AfxParseURL("http://www.ienno.com/UpFile/user/"+pMainWnd->UserName+"/"+pMainWnd->SoftID+"/update/"+pMainWnd->m_list.GetItemText(i-1,0),dwServiceType,strServer,strObject,nPort);
pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer,(LPTSTR)(LPCTSTR)strObject,nLength);
HttpSocket.Socket();
HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer);
HttpSocket.SendRequest();
HttpSocket.SetTimeout(10000,0);
char szValue[30];
HttpSocket.GetField("Content-Length",szValue,30);
int nSvrState = HttpSocket.GetServerState();
int nFileSize = atoi(szValue);
int nSize = 0;
CFile DownloadFile;
DownloadFile.Open(pMainWnd->UpPath+"\\"+pMainWnd->m_list.GetItemText(i-1,0),CFile::modeCreate | CFile::modeWrite);
char pData[1024];
int nReceSize = 0;
DWORD dwStartTime,dwEndTime;
while(nSize < nFileSize)
{
dwStartTime = GetTickCount();
nReceSize = HttpSocket.Receive(pData,1024);
if(nReceSize == 0)
{
AfxMessageBox("服务器已经关闭连接.");
break;
}
if(nReceSize == -1)
{
AfxMessageBox("接收数据超时.");
break;
}
dwEndTime = GetTickCount();
DownloadFile.Write(pData,nReceSize);
nSize += nReceSize;
pMainWnd->nCompletedSize+=nSize;
CString xxx;
xxx.Format("%d",pMainWnd->nCompletedSize);
pMainWnd->SetDlgItemText(IDC_STATIC_STATUS,xxx);
pMainWnd->m_ctrlProgress.SetPos(pMainWnd->nCompletedSize / 1024);
}
DownloadFile.Close();
}
pMainWnd->SetDlgItemText(IDC_STATIC_STATUS,"下载完毕,点击下一步更新程序");
pMainWnd->GetDlgItem(IDOK)->EnableWindow(TRUE);
return 0;
}
void CUpdateDlg::OnOK()
{
// TODO: Add extra validation here
GetDlgItem(IDOK)->EnableWindow(FALSE);
UpdateData();
m_ctrlProgress.SetRange(0,totalSize / 1024);
AfxBeginThread(DownloadThread,(void *)this);
//CDialog::OnOK();
}

nCompletedSize是int nCompletedSize的全局变量,我输出nCompletedSize的值确实在变化,但是不仅不正确,居然还出现了负数
...全文
81 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
edisonli 2008-07-27
  • 打赏
  • 举报
回复
哇,僵哥的方法确实不错,cnzdgs连变量加错了都发现了,了不起。
cnzdgs 2008-07-27
  • 打赏
  • 举报
回复
nCompletedSize是类的成员变量,不是全局变量。如果有多个线程同时使用这个变量,参考1楼的做法。
pMainWnd->nCompletedSize+=nSize;
应改为:
pMainWnd->nCompletedSize+=nReceSize;
gaoteng1984 2008-07-27
  • 打赏
  • 举报
回复
僵哥的InterlockedExchangeAdd效率更高。
但是要确保pMainWnd->nCompletedSize和nSize都是32位对齐的。默认情况下应该是对齐的,此法可行。
gaoteng1984 2008-07-27
  • 打赏
  • 举报
回复
这里需要同步,因为如果2个线程同时执行到这条语句,有可能只有其中的一个nSize最后加上去。
例如:
1. 将nSize从内存Load到EAX寄存器;
2. 将pMainWnd->nCompletedSize从内存Load到EBX寄存器;
3. EAX + EBX --> EAX
4. 将EAX写入pMainWnd->nCompletedSize
线程1执行完第3步,被换出,线程2被换入,执行完4步之后,线程1再被换入,执行第4步,这时的pMainWnd->nCompletedSize值只是原值加上线程1的nSize,线程2加的nSize没有起作用。

建议使用CriticalSection:

主线程里:
CRITICAL_SECTION lock; // 可以定义成全局变量,好让子线程访问到。
InitializeCriticalSection(&lock);
。。。
// 结束之前:
DeleteCriticalSection(&lock);

UINT CUpdateDlg::DownloadThread(void *pArg)
{
。。。
EnterCriticalSection(&lock);
pMainWnd->nCompletedSize+=nSize;
LeaveCriticalSection(&lock);
。。。
}

僵哥 2008-07-27
  • 打赏
  • 举报
回复
InterlockedExchangeAdd(&pMainWnd->nCompletedSize,nSize);

15,466

社区成员

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

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