一共有六处需要解释
这是一个多线程扫描端口的程序
我想知道,这个程序在多线程扫描时,每个线程扫描的起始和结束端口是怎么处理的
注:NowWhere是个全局变量void CMyScanPortDlg::OnStart() 
{

UpdateData(true);
if(m_threadnum<1)
{
AfxMessageBox("您至少需运行一个线程。");
return ;
}
    
DWORD dword=WaitForSingleObject(g_Busy,1000);  //解释第一处
             
if(dword==WAIT_TIMEOUT)
{
AfxMessageBox("您只能同时执行一个程序");
ReleaseSemaphore(g_Busy,1,NULL);
return;
}    GetDlgItem(IDC_STOP)->EnableWindow(true);
IsStop=false;
ReleaseSmp=false;
REPORT_SUCCEED=m_succeed;    REPORT_FAILED=m_failed;       NowWhere=m_startport;
BYTE a,b,c,d;
m_ipaddress.GetAddress(a,b,c,d);
g_message="";
threadparam1.a=a;
threadparam1.b=b;
threadparam1.c=c;
threadparam1.d=d;
threadparam1.EndPort=m_endport;
threadparam1.StartPort=m_startport;
threadparam1.hwnd=GetDlgItem(IDC_MESSAGE)->GetSafeHwnd();
for(int i=0;i<m_threadnum;i++)
AfxBeginThread(MyThread,&threadparam1,THREAD_PRIORITY_IDLE); //解释第二处      
}UINT MyThread(LPVOID pParam)         
{
THREADPARAM* threadparam=(THREADPARAM*)pParam;
sockaddr_in addr;  
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_un_b.s_b1=threadparam->a;   
addr.sin_addr.S_un.S_un_b.s_b2=threadparam->b;    addr.sin_addr.S_un.S_un_b.s_b3=threadparam->c;    addr.sin_addr.S_un.S_un_b.s_b4=threadparam->d; for(int i=threadparam->StartPort;(i<threadparam->EndPort)&&(!IsStop)&&(NowWhere<=threadparam->EndPort);i++)
{             
                 SOCKET sck_Conn;                     sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
} criticalSection.Lock(); //解释第三处
i=NowWhere;
NowWhere++;
criticalSection.Unlock();   //解释第四处 addr.sin_port=htons(i);

sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
}
int ddd=connect(sck_Conn,(sockaddr*)&addr,sizeof(addr));
CString aa="";
char buffer[80];
strcpy(buffer,"");
if(ddd==SOCKET_ERROR)
{
if(REPORT_FAILED)
aa.Format("failed!   port:%d\r\n",i); 
}
else
{
if(REPORT_SUCCEED)
aa.Format("succeed!  port:%d\r\n",i);
}
PORTPARAM *portparam=new PORTPARAM;
portparam->a=threadparam->a; 
portparam->b=threadparam->b; 
portparam->c=threadparam->c; 
portparam->d=threadparam->d;
portparam->hwnd=threadparam->hwnd; 
portparam->iPort=i; AfxBeginThread(GetPortMessage,portparam,THREAD_PRIORITY_IDLE);//解释第五处
 
closesocket(sck_Conn);
if(g_message.GetLength()>30000)
g_message="";
g_message=aa+g_message;  //CString aa="";

if(i==threadparam->EndPort)
{
g_message="scan port complete!\r\n\r\n"+g_message;
}
::SetWindowText(threadparam->hwnd,g_message);
}//for循环结束 if(!ReleaseSmp)
{
if(ReleaseSemaphore(g_Busy,1,NULL))   //解释第六处
ReleaseSmp=true;
}
return 0;
}

解决方案 »

  1.   

    这是一个多线程端口扫描程序1 g_Busy是一个全局变量,它是一个Semaphore(信号量)对象的句柄。信号量作为内核对象,起计数器的作用,当计数器达到0的时候,自动设为Singned状态。这里,是要等到信号量置零。2 THREAD_PRIORITY_IDLE,这个权限允许线程访问各个端口。这里启动扫描线程。3 criticalSection.Lock(); // 进入关键段4 criticalSection.Unlock(); // 离开关键段
    关键段是用于互斥的内核对象,当一个线程进入关键段之后,其他线程将无法进入关键段,而是挂起,直到前者离开关键段。这样,对于一些共享数据的访问就可以实现互斥了。5 和2一样6 信号量减一。你学过操作系统,对PV操作就一定不陌生。作为线程池的类似实现,通讯原语是必要的。这里的信号量,就类似于PV操作,直到所有的线程都停止,信号量才会变成0,你才有可能执行一次新的扫描,参见1。很高兴你能信任我,让我来解释这段代码中对几个内核对象的调用,不知道上面的解释你是不是满意:)
      

  2.   

    to fzd999(花差花差)
    哈 我看了一些帖子,觉得你挺棒的,解释的不错
    我对这个程序的理解(你看对不对):
    第二处 假如m_threadnum为10,这里要创建10个线程
    for(int i=0;i<m_threadnum;i++)   
       AfxBeginThread(MyThread,&threadparam1,THREAD_PRIORITY_IDLE);每个线程去执行MyThread函数,通过参数threadparam1 赋值给threadparam
    THREADPARAM* threadparam=(THREADPARAM*)pParam
    我的问题:
    然后--这里循环时,每个线程扫描的起始和结束端口是怎么确定的呢?
    for(int i=threadparam->StartPort;(i<threadparam->EndPort)&&(!IsStop)&&(NowWhere<=threadparam->EndPort);i++)能保证多个线程同步对端口进行扫描吗?
      

  3.   

    注意到这段代码了吗:
    criticalSection.Lock(); // 进入关键段
    i = NowWhere;
    NowWhere++;
    criticalSection.Unlock();   // 离开关键段
    addr.sin_port = htons(i);巧妙的地方就在这里,通过互斥的递增NowWhere来决定当前扫描的是哪个端口。
    在这个程序里面,哪一个线程扫描哪一个端口并不一定,而是每个线程进入关键段,NowWhere就是下一个要扫描的端口,拿过来扫描,同时把NowWhere加一。因为同一时间只能有一个线程进入关键段,因此端口不会被重复扫描。
    你可以进一步了解的是关键段的相关知识,加深对这段代码的理解。
      

  4.   

    还有 
    :)g_Busy是一个全局变量,它是一个Semaphore(信号量)对象的句柄。信号量作为内核对象,起计数器的作用,当计数器达到0的时候,自动设为Singned状态。这里,是要等到信号量置零g_Busy是对哪个资源起到信号量的作用criticalSection.Lock(); // 进入关键段   
    这个是对哪个资源的锁定?