//临界区变量
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
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
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期待高手
不加==20
我靠,期待高手.
不加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也不会错。
之所以没有打出30是因为第三个线程还来不及打印,程序就已经退出了
C对多执行流的唯一支持是volatile。
int iCount = 0; --> int iCount = 0;
不想多说了,自己去查查volatile。
我把代码做了一点修改如下:
//
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上面的结果应该可以说明问题。
问题就出在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;
这函数返回是失败的,我想这是原因所在,当这个函数返回返加时,thread3还没有运行
而下面的s1.Format("res:%d",iCount);
s+=s1;
iCount = 0;
AfxMessageBox(s);
所以会出现那样的结果,当运行第三线程时iCount已经为0了,
我自己认为WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
之所以会返回失败是因为当调用它时,thread1,thread2,已运行结束,而且线程运行完这后自动删除了,所以会返回失败,而加Sleep(10)
不知道是不是我的电脑比较烂的原因!
怎么我拷贝代码建立工程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);
}
也看不懂了
{
::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);
printf("%d\n", dwResult);
printf("%d", GetLastError());可以明显看出WaitForMultipleObjects返回是以失效来结束的,而并非是返回成功。而GetLastError也返回错误。查查错误原因,就清楚了,由于没有Sleep的存在,线程循环几乎是以单线程似的方式串行运行,在第三个线程压根没有分配到时间启动前,时间已经轮循到了主线程那里,这时执行
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
WaitForMultipleObjects立即发现分配过来的第三个线程句柄为无效句柄,于是不作等待,立即返回,
就这样默默的结束了整个程序,留下了一屁股后遗症。所以找到症结,要正确,在任何线程中加Sleep均可,既是在做WaitForMultipleObjects 之前就等待即可,或者干脆点说,把主线程代码量加大,只要保证线程在启动完毕前,主线程不莫名其妙的Over就可以了。
有可能在运行到给数组赋值之前线程就运行完毕了.如下就不管是否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);
到WaitForMultipleObjects,检查到两个相同地址的句柄值,即而失败返回