Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Att synkronisera resursåtkomst mellan trådar är ett vanligt problem när du skriver flertrådsprogram. Om två eller flera trådar har åtkomst till samma data samtidigt kan det leda till oönskade och oförutsägbara resultat. En tråd kan till exempel uppdatera innehållet i en struktur medan en annan tråd läser innehållet i samma struktur. Det är okänt vilka data lästråden får: gamla data, nyligen skrivna data eller möjligen en blandning av båda. MFC tillhandahåller ett antal synkroniserings- och synkroniseringsåtkomstklasser för att lösa detta problem. Det här avsnittet beskriver de tillgängliga klasserna och hur du använder dem för att skapa trådsäkra klasser i ett typiskt program med flera trådar.
Ett typiskt flertrådat program har en klass som representerar en resurs som ska delas mellan trådar. En korrekt utformad, helt trådsäker klass kräver inte att du anropar några synkroniseringsfunktioner. Allt hanteras internt i klassen, så att du kan koncentrera dig på hur du bäst använder klassen, inte på hur den kan skadas. En effektiv teknik för att skapa en helt trådsäker klass är att sammanfoga synkroniseringsklassen till resursklassen. Att slå samman synkroniseringsklasserna i den delade klassen är en enkel process.
Ta till exempel ett program som har en länkad lista med konton. Det här programmet gör att upp till tre konton kan granskas i separata fönster, men endast ett kan uppdateras vid en viss tidpunkt. När ett konto uppdateras skickas uppdaterade data via nätverket till ett dataarkiv.
Det här exempelprogrammet använder alla tre typerna av synkroniseringsklasser. Eftersom det gör att upp till tre konton kan undersökas samtidigt använder den CSemaphore för att begränsa åtkomsten till tre visningsobjekt. När ett försök att visa ett fjärde konto inträffar väntar programmet antingen tills ett av de tre första fönstren stängs eller så misslyckas det. När ett konto uppdateras använder programmet CCriticalSection för att säkerställa att endast ett konto uppdateras i taget. När uppdateringen har slutförts signalerar den CEvent, som släpper en tråd som väntar på att händelsen ska signaleras. Den här tråden skickar nya data till dataarkivet.
Utforma en Thread-Safe-klass
Om du vill göra en klass helt trådsäker lägger du först till lämplig synkroniseringsklass i de delade klasserna som datamedlem. I föregående kontohanteringsexempel skulle en CSemaphore datamedlem läggas till i vyklassen, en CCriticalSection datamedlem skulle läggas till i klassen linked-list och en CEvent datamedlem skulle läggas till i datalagringsklassen.
Lägg sedan till synkroniseringsanrop till alla medlemsfunktioner som ändrar data i klassen eller får åtkomst till en kontrollerad resurs. I varje funktion bör du skapa antingen ett CSingleLock - eller CMultiLock-objekt och anropa objektets Lock funktion. När låsobjektet hamnar utanför omfånget och förstörs, anropar objektets destruktor Unlock åt dig och släpper resursen. Naturligtvis kan du ringa Unlock direkt om du vill.
Genom att utforma din trådsäkra klass på detta sätt kan den användas i ett flertrådat program lika enkelt som en icke-trådsäker klass, men med en högre säkerhetsnivå. Att kapsla in synkroniseringsobjektet och synkroniseringsåtkomstobjektet i resursens klass ger alla fördelar med helt trådsäker programmering utan nackdelen med att underhålla synkroniseringskoden.
I följande kodexempel visas den här metoden med hjälp av en datamedlem ( m_CritSection av typen CCriticalSection), som deklareras i den delade resursklassen och ett CSingleLock -objekt. Synkroniseringen av den delade resursen (härledd från CWinThread) görs genom att skapa ett CSingleLock objekt med hjälp av objektets m_CritSection adress. Ett försök görs att låsa resursen och när den hämtas utförs arbete på det delade objektet. När arbetet är klart låsas resursen upp med ett anrop till Unlock.
CSingleLock singleLock(&m_CritSection);
singleLock.Lock();
// resource locked
//.usage of shared resource...
singleLock.Unlock();
Anmärkning
CCriticalSection, till skillnad från andra MFC-synkroniseringsklasser, har inte alternativet för en tidsbegiven låsbegäran. Väntetiden för att en tråd ska bli fri är oändlig.
Nackdelarna med den här metoden är att klassen blir något långsammare än samma klass utan att synkroniseringsobjekten läggs till. Om det finns en chans att fler än en tråd kan ta bort objektet kanske den sammanslagna metoden inte alltid fungerar. I den här situationen är det bättre att underhålla separata synkroniseringsobjekt.
Information om hur du avgör vilken synkroniseringsklass som ska användas i olika situationer finns i Multithreading: When to Use the Synchronization Classes (Multithreading: When to Use the Synchronization Classes). Mer information om synkronisering finns i Synkronisering i Windows SDK. Mer information om stöd för multitrådning i MFC finns i Multithreading with C++ and MFC (Multithreading with C++ and MFC).