//临界区变量
CRITICAL_SECTION m_sect;int iCount = 0;
void Test(LPVOID iThread)
{
int Thread = (int ) iThread;
for(int i = 1 ; i<=10 ;i ++)
{
::EnterCriticalSection(&m_sect); //Sleep(10);加上这条语句为什么结果不同 int j=iCount;
iCount++;

printf("Thread%d : icount= %d \n",Thread,iCount); ::LeaveCriticalSection(&m_sect);
}
}//创建临界区
InitializeCriticalSection(&m_sect);
//创建线程
HANDLE hThread[3];
CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)Test,(void*)1);
CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)Test,(void*)2);
CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3);

hThread[0]=pT1->m_hThread;
hThread[1]=pT2->m_hThread;
hThread[2]=pT3->m_hThread; WaitForMultipleObjects(3,hThread,TRUE,INFINITE);问题为什么结果不是30

解决方案 »

  1.   

    为什么加了Sleep()之后就不同?? 没运行过,我也不明白!!!
      

  2.   

    没有sleepC41.7 256m机器为20,有sleep为30猜解: 主线程在第三个线程启动后,进入函数体循环前退出了,第三个辅助线程来不及打印就退出了,在程序末尾加个sleep(1),既为30纯属猜测,关注正解!
      

  3.   

    我在命令行下运行也是30. vc6.0;win2000; sleep(101);配置p4 2.4g,512m
      

  4.   

    我把其中的中间结果打印出来   结果如下CRITICAL_SECTION m_sect;
    int iCount = 0;
    CString str;DWORD Test(LPVOID iThread)
    {
    int Thread = (int ) iThread;
    CFile f;
    f.Open("c:\\olio.txt",CFile::modeWrite);
    f.SeekToEnd();
    CString s;
    s.Format("-------------->thread:%d-> %d\r\n",Thread,iCount);
    f.Write(s.GetBuffer(0),s.GetLength());
    f.Close(); for(int i = 1 ; i<=10 ;i ++)
    {
    ::EnterCriticalSection(&m_sect); //Sleep(10);//加上这条语句为什么结果不同
    int j=iCount;

    CString s;
    s.Format("thread:%d-> %d\r\n",Thread,iCount);
    str += s; iCount++;
    ::LeaveCriticalSection(&m_sect);
    }
    return Thread;
    }void CZTst10View::OnT1() 
    {
    InitializeCriticalSection(&m_sect);
    //创建线程
    HANDLE hThread[3];
    CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)Test,(void*)1);
    CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)Test,(void*)2);
    CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3);

    hThread[0]=pT1->m_hThread;
    hThread[1]=pT2->m_hThread;
    hThread[2]=pT3->m_hThread; CString s;
    CString s1;
    DWORD dwret = -1;
    ::GetExitCodeThread(hThread[0],&dwret);
    s1.Format("exit:%d",dwret);
    s += s1; ::GetExitCodeThread(hThread[1],&dwret);
    s1.Format("exit:%d",dwret);
    s += s1; ::GetExitCodeThread(hThread[2],&dwret);
    s1.Format("exit:%d",dwret);
    s += s1; WaitForMultipleObjects(3,hThread,TRUE,INFINITE);

    s1.Format("res:%d",iCount);
    s+=s1;
    iCount = 0;
    AfxMessageBox(s); CFile f;
    f.Open("c:\\olio.txt",CFile::modeWrite);
    f.SeekToEnd();
    f.Write(str.GetBuffer(0),str.GetLength());
    f.Close();
    }-------------->thread:1-> 0             //第一个线程进入时
    -------------->thread:2-> 10            //第二个线程进入时
    -------------->thread:3-> 0             //第三个线程进入时   奇怪这里怎么是 0应该是20啊
    thread:1-> 0
    thread:1-> 1
    thread:1-> 2
    thread:1-> 3
    thread:1-> 4
    thread:1-> 5
    thread:1-> 6
    thread:1-> 7
    thread:1-> 8
    thread:1-> 9
    thread:2-> 10
    thread:2-> 11
    thread:2-> 12
    thread:2-> 13
    thread:2-> 14
    thread:2-> 15
    thread:2-> 16
    thread:2-> 17
    thread:2-> 18
    thread:2-> 19
    thread:3-> 0
    thread:3-> 1
    thread:3-> 2
    thread:3-> 3
    thread:3-> 4
    thread:3-> 5
    thread:3-> 6
    thread:3-> 7
    thread:3-> 8
    thread:3-> 9期待高手
      

  5.   

    加SLEEP==30
    不加==20
    我靠,期待高手.
      

  6.   

    经过多次测试,同意Caps77(厉兵秣马)的说法.
      

  7.   

    好玩...研究...
    不加Sleep,在
    hThread[0]=pT1->m_hThread;
    hThread[1]=pT2->m_hThread;
    hThread[2]=pT3->m_hThread;
    时,有的线程已经结束,CWinThread会改变m_hThread。因此WaitForMultipleObjects失效。
    如果
    hThread[0]=(HANDLE)_beginthread(Test, 0, (void*)1);
    hThread[1]=(HANDLE)_beginthread(Test, 0, (void*)2);
    hThread[2]=(HANDLE)_beginthread(Test, 0, (void*)3);
    即时不Sleep也不会错。
      

  8.   

    同意楼上,这里线程结束后CWinThread会改变m_hThread,使之失效,继而wait失效
    之所以没有打出30是因为第三个线程还来不及打印,程序就已经退出了
      

  9.   

    问题应该是在AfxBeginThread上。创建第三个线程时,第一个线程结束了,AfxBeginThread返回pT3 == pT1
      

  10.   

    C是没有进程和线程的概念。
    C对多执行流的唯一支持是volatile。
    int iCount = 0; --> int iCount = 0;
    不想多说了,自己去查查volatile。
      

  11.   

    int iCount = 0; --> volatile int iCount = 0;
      

  12.   

    我经过反复测试 我的结果是30 不知道你为什么 我VC6.0 系统XP
      

  13.   

    个人觉得是由于互斥和同步不同的原因,因为上面的CS只能保证互斥,而不能保证同步。
    我把代码做了一点修改如下:
    //
    CCriticalSection g_cs;
    int g_iCounter = 0;
    CString g_str;typedef enum{
    READ = 1,
    ADD,
    SUB
    }ACCESS;int AccessCounter(ACCESS acc, int iThread = 0)
    {
    CSingleLock lock(&g_cs);
    lock .Lock();
    CString ss;
             int iTemp;
    switch(acc)
    {
    case ADD:
    g_iCounter ++;
    ss.Format("Thread %d ADD: %d\r\n",iThread, g_iCounter);
    g_str += ss;
    break;
    case SUB:
    g_iCounter --;
    ss.Format("Thread %d SUB: %d\r\n",iThread, g_iCounter);
    g_str += ss;
    break;
    case READ:
    ss .Format("Thread %d Entered: %d\r\n", iThread, g_iCounter);
    g_str += ss;
    break;
    }
             iTemp = g_iCounter;
    lock .Unlock();
    return iTemp;
    }UINT Test(LPVOID lpvoid)
    {
    int Thread = (int ) lpvoid;

    AccessCounter(READ, Thread);
    for(int i = 1 ; i<=10 ;i ++)
    {
    //Sleep(GetTickCount() % 100);//加上这条语句为什么结果不同 AccessCounter(ADD, Thread);
    }
    return Thread;
    }void CTestDlg::OnBnClickedOk()
    {
    // TODO: 在此添加控件通知处理程序代码
    g_iCounter = 0;
    g_str = _T("");
    //创建线程
    HANDLE hThread[3];
    CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)Test,(void*)1, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
    CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)Test,(void*)2, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
    CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

    ASSERT_VALID(pT1);
    ASSERT_VALID(pT2);
    ASSERT_VALID(pT3);
    hThread[0]=pT1->m_hThread;
    hThread[1]=pT2->m_hThread;
    hThread[2]=pT3->m_hThread; pT1 ->ResumeThread();
    pT2 ->ResumeThread();
    pT3 ->ResumeThread(); WaitForMultipleObjects(3,hThread,TRUE,INFINITE); CString s;
    CString s1;
    DWORD dwret = -1;
    ::GetExitCodeThread(hThread[0],&dwret);
    s1.Format("exit:%d ",dwret);
    s += s1; ::GetExitCodeThread(hThread[1],&dwret);
    s1.Format("exit:%d ",dwret);
    s += s1; ::GetExitCodeThread(hThread[2],&dwret);
    s1.Format("exit:%d ",dwret);
    s += s1;

    s1.Format("Counter after 3 threads exited: %d", AccessCounter(READ));
    s+=s1;
    AfxMessageBox(s); g_str += s; CFile f;
    f.Open("D:\\olio.txt",CFile::modeWrite | CFile ::modeCreate);
    f.Write(g_str.GetBuffer(0), g_str.GetLength());
    f.Close();
    }
    测试结果(随机的)分别如下:
    1)没有Sleep
    Thread 3 Entered: 0
    Thread 3 ADD: 1
    Thread 3 ADD: 2
    Thread 3 ADD: 3
    Thread 3 ADD: 4
    Thread 3 ADD: 5
    Thread 3 ADD: 6
    Thread 3 ADD: 7
    Thread 3 ADD: 8
    Thread 3 ADD: 9
    Thread 3 ADD: 10
    Thread 1 Entered: 10
    Thread 1 ADD: 11
    Thread 1 ADD: 12
    Thread 1 ADD: 13
    Thread 1 ADD: 14
    Thread 1 ADD: 15
    Thread 1 ADD: 16
    Thread 1 ADD: 17
    Thread 1 ADD: 18
    Thread 1 ADD: 19
    Thread 1 ADD: 20
    Thread 2 Entered: 20
    Thread 2 ADD: 21
    Thread 2 ADD: 22
    Thread 2 ADD: 23
    Thread 2 ADD: 24
    Thread 2 ADD: 25
    Thread 2 ADD: 26
    Thread 2 ADD: 27
    Thread 2 ADD: 28
    Thread 2 ADD: 29
    Thread 2 ADD: 30
    Thread 0 Entered: 30
    exit:-1 exit:-1 exit:-1 Counter after 3 threads exited: 302)有Sleep
    Thread 3 Entered: 0
    Thread 1 Entered: 0
    Thread 2 Entered: 0
    Thread 3 ADD: 1
    Thread 1 ADD: 2
    Thread 2 ADD: 3
    Thread 3 ADD: 4
    Thread 1 ADD: 5
    Thread 2 ADD: 6
    Thread 3 ADD: 7
    Thread 1 ADD: 8
    Thread 2 ADD: 9
    Thread 3 ADD: 10
    Thread 3 ADD: 11
    Thread 3 ADD: 12
    Thread 3 ADD: 13
    Thread 1 ADD: 14
    Thread 2 ADD: 15
    Thread 3 ADD: 16
    Thread 1 ADD: 17
    Thread 2 ADD: 18
    Thread 3 ADD: 19
    Thread 3 ADD: 20
    Thread 1 ADD: 21
    Thread 2 ADD: 22
    Thread 1 ADD: 23
    Thread 2 ADD: 24
    Thread 1 ADD: 25
    Thread 2 ADD: 26
    Thread 1 ADD: 27
    Thread 2 ADD: 28
    Thread 1 ADD: 29
    Thread 2 ADD: 30
    Thread 0 Entered: 30
    exit:-1 exit:-1 exit:-1 Counter after 3 threads exited: 30上面的结果应该可以说明问题。
      

  14.   

    这个问题你只要研究一下MFC的源码就明白了AfxBeginThread调用后,会创建一个CWinThread对象,然后用beginthreadex创建一个线程,线程创建成功后,返回CWinThread指针。
    问题就出在MFC的内部处理上,在
    UINT APIENTRY _AfxThreadEntry(void* pParam)
    的函数结尾处会调用
    AfxEndThread(nResult);

    void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)
    {
    #ifndef _MT
    nExitCode;
    bDelete;
    #else
    // remove current CWinThread object from memory
    AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
    CWinThread* pThread = pState->m_pCurrentWinThread;
    if (pThread != NULL)
    {
    ASSERT_VALID(pThread);
    ASSERT(pThread != AfxGetApp()); // cleanup OLE if required
    if (pThread->m_lpfnOleTermOrFreeLib != NULL)
    (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE); if (bDelete)
    pThread->Delete();
    pState->m_pCurrentWinThread = NULL;
    } // allow cleanup of any thread local objects
    AfxTermThread(); // allow C-runtime to cleanup, and exit the thread
    _endthreadex(nExitCode);
    #endif //!_MT
    }bDelete缺省是TRUE
    所以会调用CWinThread的delete 函数
    void CWinThread::Delete()
    {
    // delete thread if it is auto-deleting
    if (m_bAutoDelete)
    delete this;
    }m_bAutoDelete缺省也是TRUE
    所以执行的最后CwinThread会把自身删除掉,包括关掉线程句柄。直接用SDK开发,就没有这个问题了。如果用MFC的话,可以这么处理
    InitializeCriticalSection(&m_sect);
    //创建线程
    HANDLE hThread[3];
    CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)Test,(void*)1,0,0,CREATE_SUSPENDED);
    CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)Test,(void*)2,0,0,CREATE_SUSPENDED);
    CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3,0,0,CREATE_SUSPENDED);
    pT1->m_bAutoDelete = FALSE;
    pT2->m_bAutoDelete = FALSE;
    pT3->m_bAutoDelete = FALSE;

    hThread[0]=pT1->m_hThread;
    hThread[1]=pT2->m_hThread;
    hThread[2]=pT3->m_hThread;
    pT1->ResumeThread();
    pT2->ResumeThread();
    pT3->ResumeThread();
    DWORD dwRet = WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
    delete pT1;
    delete pT2;
    delete pT3;
      

  15.   

    WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
    这函数返回是失败的,我想这是原因所在,当这个函数返回返加时,thread3还没有运行
    而下面的s1.Format("res:%d",iCount);
    s+=s1;
    iCount = 0;
    AfxMessageBox(s);
    所以会出现那样的结果,当运行第三线程时iCount已经为0了,
    我自己认为WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
    之所以会返回失败是因为当调用它时,thread1,thread2,已运行结束,而且线程运行完这后自动删除了,所以会返回失败,而加Sleep(10)
      

  16.   

    后,WaitForMultipleObjects(3,hThread,TRUE,INFINITE);运行时,thread1,thread2还没有运行结束,对象存在,返回成功,所以结果是正确的
      

  17.   

    在控制台下测试,不管加不加SLEEP都返回30
    不知道是不是我的电脑比较烂的原因!
      

  18.   

    天哪,我晕了
    怎么我拷贝代码建立工程Build发生错误,
    如下:
    #include <stdio.h>
    CRITICAL_SECTION m_sect;int iCount = 0;void Test(LPVOID iThread)
    {
    int Thread = (int ) iThread;
    for(int i = 1 ; i<=10 ;i ++)
    {
    ::EnterCriticalSection(&m_sect);

    //Sleep(10);加上这条语句为什么结果不同

    int j=iCount;
    iCount++;

    printf("Thread%d : icount= %d \n",Thread,iCount);

    ::LeaveCriticalSection(&m_sect);
    }
    }
     void main()

    //////////////////////////////////////////////////////////
    //创建临界区
    InitializeCriticalSection(&m_sect);
    //创建线程
    HANDLE hThread[3];
    CWinThread* pT1=AfxBeginThread((AFX_THREADPROC)Test,(void*)1);
    CWinThread* pT2=AfxBeginThread((AFX_THREADPROC)Test,(void*)2);
    CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3);

    hThread[0]=pT1->m_hThread;
    hThread[1]=pT2->m_hThread;
    hThread[2]=pT3->m_hThread;

    WaitForMultipleObjects(3,hThread,TRUE,INFINITE);

    }
      

  19.   

    太难了,MFC太难了,放弃了
    也看不懂了
      

  20.   

    for(int i = 1 ; i<=10 ;i ++)
    {
    ::EnterCriticalSection(&m_sect); //Sleep(10);加上这条语句为什么结果不同 int j=iCount;
    iCount++;

    printf("Thread%d : icount= %d \n",Thread,iCount); ::LeaveCriticalSection(&m_sect);
    }
    修改成下边的呢?::EnterCriticalSection(&m_sect);
    for(int i = 1 ; i<=10 ;i ++)
    {
    //Sleep(10);加上这条语句为什么结果不同 int j=iCount;
    iCount++;

    printf("Thread%d : icount= %d \n",Thread,iCount);
    }
    ::LeaveCriticalSection(&m_sect);
      

  21.   

    要有根据,最简单就是加些调试!DWORD dwResult = WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
    printf("%d\n", dwResult);
    printf("%d", GetLastError());可以明显看出WaitForMultipleObjects返回是以失效来结束的,而并非是返回成功。而GetLastError也返回错误。查查错误原因,就清楚了,由于没有Sleep的存在,线程循环几乎是以单线程似的方式串行运行,在第三个线程压根没有分配到时间启动前,时间已经轮循到了主线程那里,这时执行
    WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
    WaitForMultipleObjects立即发现分配过来的第三个线程句柄为无效句柄,于是不作等待,立即返回,
    就这样默默的结束了整个程序,留下了一屁股后遗症。所以找到症结,要正确,在任何线程中加Sleep均可,既是在做WaitForMultipleObjects 之前就等待即可,或者干脆点说,把主线程代码量加大,只要保证线程在启动完毕前,主线程不莫名其妙的Over就可以了。
      

  22.   

    正如ndy_w(carpe diem)说的那样,
    有可能在运行到给数组赋值之前线程就运行完毕了.如下就不管是否sleep就没问题了.
    hThread[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Test, (void*)1, 0, NULL);
    hThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Test, (void*)2, 0, NULL);
    hThread[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Test, (void*)3, 0, NULL);
      

  23.   

    因为启动线程是异步的,如果运行的太快,线程还没有启动完成时,线程HANDLE肯定是无效的,因此在执行WaitForMultipleObjects时变反回了。
      

  24.   

    执行到CWinThread* pT3=AfxBeginThread((AFX_THREADPROC)Test,(void*)3);时第一个线程已经执行完,并且释放了所用的内存,pT3这时正好申请到了pT1用过的内存.地址相同.
    到WaitForMultipleObjects,检查到两个相同地址的句柄值,即而失败返回