Interlocked系列函數線程同步的缺陷

1、 Code

int	Work()
{
	while (m_lInterlockedData < 10)
	{
		InterlockedIncrement(&m_lInterlockedData);			
		Sleep(100);
	}

	printf("CInterlocked::Work end\n");

	return	0;
}

5個線程運行Work()函數,理論上m_lInterlockedData最後運行的結果應該是10
BOOL	RunThread()
{
	CloseHandle((HANDLE)_beginthreadex(NULL, NULL, ThreadProc, this, NULL, NULL));
	CloseHandle((HANDLE)_beginthreadex(NULL, NULL, ThreadProc, this, NULL, NULL));
	CloseHandle((HANDLE)_beginthreadex(NULL, NULL, ThreadProc, this, NULL, NULL));
	CloseHandle((HANDLE)_beginthreadex(NULL, NULL, ThreadProc, this, NULL, NULL));
	CloseHandle((HANDLE)_beginthreadex(NULL, NULL, ThreadProc, this, NULL, NULL));

	return	TRUE;
}

2、 運行結果

實際運行結果卻令人意外,m_lInterlockedData = 11, why?

3、 原因
做以下假設:
3.1 m_lInterlockedData = 9時,線程運行完while(m_lInterlockedData < 10) ,會判斷爲真。
3.2 此時系統切換到線程運行,線程2Work函數會將m_lInterlockedData增加到10
3.3 系統再次切換返回到線程1運行,由於while的判定代碼已執行且爲真,所以此時會執行InterlockedIncrement(&m_lInterlockedData);從而將m_lInterlockedData再次增加到11

4、 解決方法
改用臨界區即可解決如上問題
int	WorkEx()
{
	while (TRUE)
	{
		EnterCriticalSection(&m_cs);
		if (m_lInterlockedData < 10)
		{
			m_lInterlockedData++;
			LeaveCriticalSection(&m_cs);
		}
		else
		{
			LeaveCriticalSection(&m_cs);
			break;
		}
		
		Sleep(100);
	}
	
	printf("CInterlocked::Work end\n");
	
	return	0;
}
注意,爲了不讓在臨近區中等待過久,故將Sleep(100) 放在LeaveCriticalSection() 之外。

發佈了27 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章