我这线程问题多的没法说了  哪位高人能帮忙找些错误出来?
在表格里数据显示也有问题UINT nSinglePort;TCHAR temp[10] = "\0";
m_cProgress.SetPos(0); //设置进度条当前位置
m_cResult.DeleteAllItems(); //删除列表所有的项,不然新的就会加到原来项的后面
//清空列表框
POSITION p = m_pStatusList->GetHeadPosition();//建立初始位置,并返回结点指针
while (p)
{
  POSITION temp = p;
  DATA* pNode = (DATA*)m_pStatusList->GetNext(p);//获取用于反复的下一个元素
  m_pStatusList->RemoveAt(temp);//删除指定位置处的节点
  //循环删除
  if (pNode)
   delete pNode;
}
////验证IP地址是否为空
//if (m_cIP.IsBlank())
//{
//  MessageBox(_T("请输入IP地址."),
//   _T("Error"),
//   MB_OK | MB_ICONEXCLAMATION);
//  return;
//}
//BYTE f1,f2,f3,f4;
////验证IP地址是否正确
//if (m_cIP.GetAddress(f1,f2,f3,f4) < 4)//有效区域小于4
//{
//  MessageBox(_T("请确认IP地址."),
//   _T("Invalid IP address"),MB_OK | MB_ICONEXCLAMATION);
//  return;
//}
//进行IP地址转化
//CString btnTxt,IP;
//IP = _itoa(f1,temp,10);//将整数IP转化为一个字符串
//IP += _T('.');
//IP += _itoa(f2,temp,10);//将整数IP转化为一个字符串
//IP += _T('.');
//IP += _itoa(f3,temp,10);//将整数IP转化为一个字符串
//IP += _T('.');
//IP += _itoa(f4,temp,10);//将整数IP转化为一个字符串
IP="123.9.212.55";
m_cBtnStop.EnableWindow();
m_cBtnScan.EnableWindow(FALSE);
//是否是单个端口扫描
if (m_bSinglePort) //如果单个扫描值不为0
{
  CString port;
  m_cSinglePort.GetWindowText(port);//获取单扫描文本控件内的数据
  
  m_minPort = m_maxPort = nSinglePort = atoi(port);//将字符串转换为整数类型
}
else//多端口
{
  
  CString port1,port2;
  m_cPortFrom.GetWindowText(port1);//获取多个扫描文本控件内的数据
  m_cPortTo.GetWindowText(port2);//获取多个扫描文本控件内的数据
  m_minPort = atoi(port1);//将字符串转换为整数类型
  m_maxPort = atoi(port2);//将字符串转换为整数类型
  m_cProgress.SetRange32(0,m_maxPort-m_minPort+1);//进度栏的最小值与最大值
  m_cProgress.SetStep(1);//设置进度栏步长
}if (!m_bSinglePort && m_maxPort < m_minPort)//错误判断
{
  MessageBox(_T("最大端口要大于最小端口."),
   _T("Caution"),
   MB_OK | MB_ICONINFORMATION);
  return;
}
UINT m_nMaxAttempts = GetDlgItemInt(IDC_EDIT_ATTEMPTS);//将扫描次数的内容转换为整形数据
for (m_nCounter = m_minPort; m_nCounter <= m_maxPort; m_nCounter++)//循环扫描端口
{

  AfxBeginThread(&CPortScanView::thread,this);
  
   MSG message;
  //以下消息用于等待Post出去的消息被响应,或者在限定时间内任务是否成功执行
  //以下消息可以在执行这个函数时不至于没办法响应用户的操作
  if (::PeekMessage(&message,NULL,0,0,PM_REMOVE))//为一个消息检查线程消息队列,并将该消息(如果存在)放于指定的结构。PM_REMOVE:PeekMessage处理后,消息从队列里除掉。
  {
   ::TranslateMessage(&message);//该函数将虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。
   ::DispatchMessage(&message);//该函数调度一个消息给窗口程序
  }
  m_cProgress.StepIt();//按照当前步长更新进度栏位置
}
//设定状态栏
m_parent->SetStatusBarText((CString)_T("完毕"));//状态栏上显示文字
m_cBtnScan.EnableWindow();
m_cBtnStop.EnableWindow(FALSE);UINT CPortScanView::thread(LPVOID param1)
{
//((CPortScanView*)param1)->critical_section.Lock();
CPortScanView *param= new CPortScanView; param=(CPortScanView*)param1;
// ((CPortScanView*)param1)->critical_section.Unlock();
BOOL bIsOpen = FALSE;
  UINT nAttempt = 1;
  TCHAR temp[10]="\0";
  UINT nIndex = 0;//索引
  while(nAttempt <= ((CPortScanView*)param)->m_nMaxAttempts && !bIsOpen)//扫描次数并且标记不为假
  {
   
   CString str = _T("连接端口# ");
   #ifdef _UNICODE
   str += _itow(m_nCounter,temp,10);
   #else
   str += itoa(((CPortScanView*)param)->m_nCounter,temp,10);//将整数端口转化为一个字符串
   #endif
   str += _T(", IP地址=");
   str += ((CPortScanView*)param)->IP;
   str += _T(", Attempt=");
   #ifdef _UNICODE
   str += _itow(nAttempt,temp,10);
   #else
   str += itoa(nAttempt,temp,10);//将整数次数转化为一个字符串
   #endif
  
   //设定状态栏
   ((CPortScanView*)param)->m_parent->SetStatusBarText(str);//在状态栏显示字符串
   str.Empty();//str的值变了. 将NULL字节放入CString
 CTheSocket* pSocket;//Socket的派生类
pSocket = new CTheSocket;
ASSERT(pSocket);//如果条件返回错误,则终止程序执行
//创建socket
if (!pSocket->Create())//产生一个Socket句柄
{
  //如果创建失败,则删除,返回 false
  delete pSocket;
  pSocket = NULL;
  bIsOpen = FALSE;
}
//AfxMessageBox(itoa(((CPortScanView*)param)->m_nCounter,temp,10)) ;
//连接被连接的主机地址和指定端口
while (!pSocket->Connect(((CPortScanView*)param)->IP, ((CPortScanView*)param)->m_nCounter))//与未连接的数据流或数据报套接字进行连接(IP,端口)
{
  //如果失败返回false
  delete pSocket;
  pSocket = NULL;
  break;
 // return FALSE;
}
//关闭Socket 连接并释放所有关联的资源
//pSocket->Close();
delete pSocket;
//return TRUE;//((CPortScanView*)param)->critical_section.Lock();
   if (bIsOpen)//如果连接成功
   {
    DATA* pNode = new DATA;//自定义结构
    ASSERT(pNode);//如果条件返回错误,则终止程序执行
    //IP.GetLength()将返回字符串所占字节的数目
    //GetBuffer为一个CString对象重新获取CString中的字符buffer,返回的LPTSTR为非const的
    strcpy(pNode->IPAddress,((CPortScanView*)param)->IP.GetBuffer(((CPortScanView*)param)->IP.GetLength()));//把IP拷贝到DATA结构体的IPAddress
    strcpy(pNode->port,_itoa(((CPortScanView*)param)->m_nCounter,temp,10));//将端口转换为字符拷贝到DATA结构体的port
    pNode->bStatus = 1;//打开状态 1 = open , 0 = close
    pNode->nAttempts = nAttempt;//扫描次数
((CPortScanView*)param)->AddItem(nIndex,0,((CPortScanView*)param)->IP);//在表格内添加IP记录
  ((CPortScanView*)param)->AddItem(nIndex,1,itoa(((CPortScanView*)param)->m_nCounter,temp,10));//在表格内添加端口记录
  if (bIsOpen)
  {
   ((CPortScanView*)param)->AddItem(nIndex,2,_T("打开"));
   ((CPortScanView*)param)->AddItem(nIndex,4,_T("*"));
  }
  else
  {
   ((CPortScanView*)param)->AddItem(nIndex,2,_T("关闭"));
   ((CPortScanView*)param)->AddItem(nIndex,4,_T(" "));
  }
  ((CPortScanView*)param)->AddItem(nIndex++,3,_itoa(1,temp,10));///在表格内添加扫描次数    //((CPortScanView*)param)->m_pStatusList->AddTail(pNode);//将一个元素(或另一个数组中的所有元素)添加到列表的尾部(产生一个新的尾部)    }
   //试图连接次数
   nAttempt++;//次数++
  
  //如果还是无法扫描成功
  if (!bIsOpen)//如果连接失败
  {
   DATA* pNode = new DATA;//自定义结构
   ASSERT(pNode);//如果条件返回错误,则终止程序执行
   //IP.GetLength()将返回字符串所占字节的数目
   //GetBuffer为一个CString对象重新获取CString中的字符buffer,返回的LPTSTR为非const的
   strcpy(pNode->IPAddress,((CPortScanView*)param)->IP.GetBuffer(((CPortScanView*)param)->IP.GetLength()));//把IP拷贝到DATA结构体的IPAddress
   
   strcpy(pNode->port,_itoa(((CPortScanView*)param)->m_nCounter,temp,10));//将端口转换为字符拷贝到DATA结构体的port
   pNode->bStatus = 0; //关闭状态 1 = open , 0 = close
   pNode->nAttempts = nAttempt-1;//扫描次数--
  ((CPortScanView*)param)->AddItem(nIndex,0,((CPortScanView*)param)->IP);//在表格内添加IP记录
  ((CPortScanView*)param)->AddItem(nIndex,1,itoa(((CPortScanView*)param)->m_nCounter,temp,10));//在表格内添加端口记录
  if (bIsOpen)
  {
   ((CPortScanView*)param)->AddItem(nIndex,2,_T("打开"));
   ((CPortScanView*)param)->AddItem(nIndex,4,_T("*"));
  }
  else
  {
   ((CPortScanView*)param)->AddItem(nIndex,2,_T("关闭"));
   ((CPortScanView*)param)->AddItem(nIndex,4,_T(" "));
  }
  ((CPortScanView*)param)->AddItem(nIndex++,3,_itoa(1,temp,10));///在表格内添加扫描次数
   //((CPortScanView*)param)->m_pStatusList->AddTail(pNode);//将一个元素(或另一个数组中的所有元素)添加到列表的尾部(产生一个新的尾部) 
  
  }
//((CPortScanView*)param)->critical_section.Unlock();
}
 
//POSITION pos = ((CPortScanView*)param)->m_pStatusList->GetHeadPosition();//建立初始位置,并返回结点指针
////循环插入扫描结果
//
//
// // DATA* pNode;// = (DATA*)((CPortScanView*)param)->m_pStatusList->GetNext(pos);//获取用于反复的下一个元素
//  ((CPortScanView*)param)->AddItem(nIndex,0,((CPortScanView*)param)->IP);//在表格内添加IP记录
//  ((CPortScanView*)param)->AddItem(nIndex,1,itoa(((CPortScanView*)param)->m_nCounter,temp,10));//在表格内添加端口记录
//  if (bIsOpen)
//  {
//   ((CPortScanView*)param)->AddItem(nIndex,2,_T("打开"));
//   ((CPortScanView*)param)->AddItem(nIndex,4,_T("*"));
//  }
//  else
//  {
//   ((CPortScanView*)param)->AddItem(nIndex,2,_T("关闭"));
//   ((CPortScanView*)param)->AddItem(nIndex,4,_T(" "));
//  }
//  ((CPortScanView*)param)->AddItem(nIndex++,3,_itoa(1,temp,10));///在表格内添加扫描次数  return 0;
}

解决方案 »

  1.   

    线程里N处用到了线程入参传入的CPortScanView的指针,这是最大的不合理。
    1、对CPortScanView内的方法的调用都是线程不安全的,需要做同步
    2、就算做了同步,这样的程序结构也是不合理的,因为如果CPortScanView方法做了同步,那线程还有何意义,因为互相都阻塞了,再说传递全局对象指针进入线程并做大规模调用,那是相当不推荐的做法。
    3、线程内while循环内建议在必要的地方加上sleep至少1毫秒,以避免CPU 100%
    4、要保证程序退出后,如线程执行在一半,也能正常退出,所以就要求你能保证线程退出时CPortScanView指针所指对象等主线程对象还没被析构。
      

  2.   

    UI线程专门处理UI,工作线程专门处理数据,如果数据更新了,工作线程应该向UI线程中的窗口发送消息,在UI线程中完成窗口内容更新。
      

  3.   

    CPortScanView *param= new CPortScanView;不要在工作线程中创建UI界面, 创建界面线程用CreateThread