共用方式為


多執行緒:如何使用 MFC 同步處理類別

在寫入多執行緒應用程式時,同步處理執行緒之間的資源存取是常見的問題。 讓兩個以上的執行緒同時存取相同的資料,可能會導致非預期且無法預測的結果。 例如,一個執行緒可能會更新結構的內容,而另一個執行緒正在讀取相同結構的內容。 讀取執行緒將接收的資料未知:舊資料、新寫入的資料,或兩者可能混合。 MFC 提供一些同步處理和同步處理存取類別,以協助解決此問題。 本主題說明可用的類別,以及如何使用這些類別在一般多執行緒應用程式中建立安全線程類別。

典型的多執行緒應用程式有一個類別,代表線上程之間共用的資源。 設計正確、完全安全線程的類別不需要您呼叫任何同步處理函式。 所有專案都會在類別內部處理,讓您專注于如何最好地使用 類別,而不是它可能如何損毀。 建立完全安全線程類別的有效技巧是將同步處理類別合併到資源類別。 將同步處理類別合併到共用類別是一個直接的程式。

例如,採用維護帳戶連結清單的應用程式。 此應用程式允許在個別視窗中檢查最多三個帳戶,但在任何特定時間只能更新一個帳戶。 更新帳戶時,會透過網路將更新的資料傳送至資料封存。

這個範例應用程式會使用這三種類型的同步處理類別。 因為它允許一次檢查最多三個帳戶,所以它會使用 CSemaphore 來限制對三個檢視物件的存取。 嘗試檢視第四個帳戶時,應用程式會等到前三個視窗的其中一個關閉或失敗。 更新帳戶時,應用程式會使用 CCriticalSection 來確保一次只會更新一個帳戶。 更新成功之後,它會發出 CEvent 的訊號 ,這會釋放等候事件發出訊號的執行緒。 此執行緒會將新資料傳送至資料封存。

設計執行緒保管庫類別

若要讓類別完全安全線程,請先將適當的同步處理類別新增至共用類別做為資料成員。 在先前的帳戶管理範例中, CSemaphore 資料成員會新增至檢視類別、 CCriticalSection 資料成員會新增至連結清單類別,並將 CEvent 資料成員新增至資料儲存體類別。

接下來,將同步處理呼叫新增至修改 類別中資料或存取受控制資源的所有成員函式。 在每個函式中,您應該建立 CSingleLock 或 CMultiLock 物件,並呼叫該物件的 Lock 函式。 當鎖定物件超出範圍並終結時,物件的解構函式會為您呼叫 Unlock ,釋放資源。 當然,如有需要,您可以直接呼叫 Unlock

以這種方式設計執行緒安全類別可讓您輕鬆地在多執行緒應用程式中使用,就像非執行緒安全類別一樣,但具有較高層級的安全性。 將同步處理物件和同步存取物件封裝到資源的 類別,可提供完全安全線程程式設計的所有優點,而不需要維護同步處理常式代碼的缺點。

下列程式碼範例示範這個方法,方法是使用在共用資源類別和 CSingleLock 物件中宣告的資料成員 m_CritSection (屬於 類型 CCriticalSection )。 使用 物件的位址建立 CSingleLock 物件,嘗試同步處理共用資源(衍生自 CWinThread )。 m_CritSection 嘗試鎖定資源,並在取得時在共用物件上完成工作。 當工作完成時,資源會解除鎖定, Unlock 並呼叫 。

CSingleLock singleLock(&m_CritSection);
singleLock.Lock();
// resource locked
//.usage of shared resource...

singleLock.Unlock();

注意

CCriticalSection不同于其他 MFC 同步處理類別,沒有計時鎖定要求的選項。 等候執行緒變成可用期間是無限的。

此方法的缺點是,類別會比相同類別稍微慢一點,而不會新增同步處理物件。 此外,如果可能會有一個以上的執行緒可能會刪除物件,合併的方法可能不一定能夠運作。 在此情況下,最好維護個別的同步處理物件。

如需判斷在不同情況下要使用的同步處理類別的相關資訊,請參閱 多執行緒:何時使用同步處理類別 。 如需同步處理的詳細資訊,請參閱 Windows SDK 中的同步 處理。 如需 MFC 中多執行緒支援的詳細資訊,請參閱 使用 C++ 和 MFC 進行多執行緒處理。

另請參閱

使用 C++ 和 MFC 進行多執行緒處理