Multithreading: Suggerimenti per la programmazione MFC
Le applicazioni multithreading richiedono una maggiore attenzione rispetto alle applicazioni a thread singolo per garantire che le operazioni si verifichino nell'ordine previsto e che tutti i dati a cui si accede da più thread non siano danneggiati. Questo argomento illustra le tecniche per evitare potenziali problemi durante la programmazione di applicazioni multithreading con la libreria MFC (Microsoft Foundation Class).
Accesso a oggetti da più thread
Gli oggetti MFC non sono thread-safe da soli. Due thread separati non possono modificare lo stesso oggetto a meno che non si usino le classi di sincronizzazione MFC e/o gli oggetti di sincronizzazione Win32 appropriati, ad esempio sezioni critiche. Per altre informazioni sulle sezioni critiche e altri oggetti correlati, vedere Sincronizzazione in Windows SDK.
La libreria di classi usa sezioni critiche internamente per proteggere le strutture di dati globali, ad esempio quelle usate dall'allocazione di memoria di debug.
Accesso agli oggetti MFC da thread non MFC
Se si dispone di un'applicazione multithreading che crea un thread in modo diverso dall'uso di un oggetto CWinThread , non è possibile accedere ad altri oggetti MFC da tale thread. In altre parole, se si vuole accedere a qualsiasi oggetto MFC da un thread secondario, è necessario creare tale thread con uno dei metodi descritti in Multithreading: Creazione di thread dell'interfaccia utente o multithreading: creazione di thread di lavoro. Questi metodi sono gli unici che consentono alla libreria di classi di inizializzare le variabili interne necessarie per gestire le applicazioni multithreading.
Mappe handle di Windows
Come regola generale, un thread può accedere solo agli oggetti MFC creati. Ciò è dovuto al fatto che le mappe di handle di Windows temporanee e permanenti vengono mantenute nella risorsa di archiviazione locale del thread per mantenere la protezione dall'accesso simultaneo da più thread. Ad esempio, un thread di lavoro non può eseguire un calcolo e quindi chiamare la funzione membro di UpdateAllViews
un documento per fare in modo che le finestre contenenti visualizzazioni sui nuovi dati siano state modificate. Ciò non ha alcun effetto, perché la mappa da CWnd
oggetti a HWND è locale al thread primario. Ciò significa che un thread potrebbe avere un mapping da un handle di Windows a un oggetto C++, ma un altro thread potrebbe eseguire il mapping dello stesso handle a un oggetto C++ diverso. Le modifiche apportate in un thread non vengono riflesse nell'altro.
Esistono diversi modi per risolvere questo problema. Il primo consiste nel passare singoli handle (ad esempio un HWND) anziché oggetti C++ al thread di lavoro. Il thread di lavoro aggiunge quindi questi oggetti alla relativa mappa temporanea chiamando la funzione membro appropriata FromHandle
. È anche possibile aggiungere l'oggetto alla mappa permanente del thread chiamando Attach
, ma questa operazione deve essere eseguita solo se si garantisce che l'oggetto esista più a lungo del thread.
Un altro metodo consiste nel creare nuovi messaggi definiti dall'utente corrispondenti alle diverse attività eseguite dai thread di lavoro e inserire questi messaggi nella finestra principale dell'applicazione usando ::PostMessage
. Questo metodo di comunicazione è simile a due diverse applicazioni conversando, ad eccezione del fatto che entrambi i thread vengono eseguiti nello stesso spazio indirizzi.
Per altre informazioni sulla gestione delle mappe, vedere La nota tecnica 3. Per altre informazioni sull'archiviazione locale dei thread, vedere Archiviazione locale dei thread e Uso dell'archiviazione locale del thread in Windows SDK.
Comunicazione tra thread
MFC fornisce una serie di classi che consentono ai thread di sincronizzare l'accesso agli oggetti per mantenere la thread safety. L'utilizzo di queste classi è descritto in Multithreading: Come usare le classi di sincronizzazione e il multithreading: quando usare le classi di sincronizzazione. Per altre informazioni su questi oggetti, vedere Sincronizzazione in Windows SDK.