Multithreading e impostazioni locali
Sia la libreria di runtime C che la libreria standard C++ forniscono supporto per la modifica delle impostazioni locali del programma. Questo argomento illustra i problemi che si verificano quando si usa la funzionalità delle impostazioni locali di entrambe le librerie in un'applicazione multithreading.
Osservazioni:
Con la libreria di runtime C è possibile creare applicazioni multithreading usando le _beginthread
funzioni e _beginthreadex
. Questo argomento illustra solo le applicazioni multithreading create usando queste funzioni. Per altre informazioni, vedere _beginthread, _beginthreadex.
Per modificare le impostazioni locali usando la libreria di runtime C, usare la funzione setlocale . Nelle versioni precedenti di Visual C++, questa funzione modifica sempre le impostazioni locali nell'intera applicazione. È ora disponibile il supporto per l'impostazione delle impostazioni locali per ogni thread. Questa operazione viene eseguita usando la funzione _configthreadlocale . Per specificare che setlocale deve modificare solo le impostazioni locali nel thread corrente, chiamare _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
in tale thread. Al contrario, la chiamata _configthreadlocale(_DISABLE_PER_THREAD_LOCALE)
causerà l'uso delle impostazioni locali globali del thread e qualsiasi chiamata a setlocale in tale thread modificherà le impostazioni locali in tutti i thread che non hanno abilitato in modo esplicito le impostazioni locali per ogni thread.
Per modificare le impostazioni locali usando la libreria di runtime C++, usare la classe delle impostazioni locali. Chiamando il metodo locale::global , si modificano le impostazioni locali in ogni thread che non ha abilitato in modo esplicito le impostazioni locali per thread. Per modificare le impostazioni locali in un singolo thread o parte di un'applicazione, è sufficiente creare un'istanza di un locale
oggetto in tale thread o parte di codice.
Nota
La chiamata a locale::global modifica le impostazioni locali sia per la libreria standard C++ che per la libreria di runtime C. Tuttavia, la chiamata a setlocale modifica solo le impostazioni locali per la libreria di runtime C. La libreria standard C++ non è interessata.
Negli esempi seguenti viene illustrato come usare la funzione setlocale, la classe delle impostazioni locali e la funzione _configthreadlocale per modificare le impostazioni locali di un'applicazione in diversi scenari.
Esempio: Modificare le impostazioni locali con le impostazioni locali per thread abilitate
In questo esempio il thread principale genera due thread figlio. Il primo thread, Thread A, abilita le impostazioni locali per thread chiamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Il secondo thread, Thread B e il thread principale, non abilitano le impostazioni locali per thread. Thread A quindi procede per modificare le impostazioni locali usando la funzione setlocale della libreria di runtime C.
Poiché le impostazioni locali per thread A sono abilitate, solo le funzioni della libreria di runtime C nel thread A iniziano a usare le impostazioni locali "francese". Le funzioni della libreria di runtime C nel thread B e nel thread principale continuano a usare le impostazioni locali "C". Inoltre, poiché setlocale non influisce sulle impostazioni locali della libreria standard C++, tutti gli oggetti della libreria standard C++ continuano a usare le impostazioni locali "C".
// multithread_locale_1.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>
#define NUM_THREADS 2
using namespace std;
unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);
BOOL localeSet = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);
int main()
{
HANDLE threads[NUM_THREADS];
unsigned aID;
threads[0] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadA, NULL, 0, &aID);
unsigned bID;
threads[1] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadB, NULL, 0, &bID);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
printf_s("[Thread main] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread main] locale::global is set to \"%s\"\n",
locale().name().c_str());
CloseHandle(threads[0]);
CloseHandle(threads[1]);
CloseHandle(printMutex);
return 0;
}
unsigned __stdcall RunThreadA(void *params)
{
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
setlocale(LC_ALL, "french");
localeSet = TRUE;
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread A] Per-thread locale is enabled.\n");
printf_s("[Thread A] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
unsigned __stdcall RunThreadB(void *params)
{
while (!localeSet)
Sleep(100);
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
printf_s("[Thread B] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "French_France.1252"
[Thread A] locale::global is set to "C"
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "C"
[Thread B] locale::global is set to "C"
[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "C"
[Thread main] locale::global is set to "C"
Esempio: Modificare le impostazioni locali globali con le impostazioni locali per thread abilitate
In questo esempio il thread principale genera due thread figlio. Il primo thread, Thread A, abilita le impostazioni locali per thread chiamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Il secondo thread, Thread B e il thread principale, non abilitano le impostazioni locali per thread. Thread A quindi procede per modificare le impostazioni locali usando il metodo locale::global della libreria standard C++.
Poiché le impostazioni locali per thread A sono abilitate, solo le funzioni della libreria di runtime C nel thread A iniziano a usare le impostazioni locali "francese". Le funzioni della libreria di runtime C nel thread B e nel thread principale continuano a usare le impostazioni locali "C". Tuttavia, poiché il metodo locale::global modifica le impostazioni locali "globalmente", tutti gli oggetti della libreria standard C++ in tutti i thread iniziano a usare le impostazioni locali "francese".
// multithread_locale_2.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>
#define NUM_THREADS 2
using namespace std;
unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);
BOOL localeSet = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);
int main()
{
HANDLE threads[NUM_THREADS];
unsigned aID;
threads[0] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadA, NULL, 0, &aID);
unsigned bID;
threads[1] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadB, NULL, 0, &bID);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
printf_s("[Thread main] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread main] locale::global is set to \"%s\"\n",
locale().name().c_str());
CloseHandle(threads[0]);
CloseHandle(threads[1]);
CloseHandle(printMutex);
return 0;
}
unsigned __stdcall RunThreadA(void *params)
{
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
locale::global(locale("french"));
localeSet = TRUE;
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread A] Per-thread locale is enabled.\n");
printf_s("[Thread A] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
unsigned __stdcall RunThreadB(void *params)
{
while (!localeSet)
Sleep(100);
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
printf_s("[Thread B] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "French_France.1252"
[Thread A] locale::global is set to "French_France.1252"
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "C"
[Thread B] locale::global is set to "French_France.1252"
[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "C"
[Thread main] locale::global is set to "French_France.1252"
Esempio: Modificare le impostazioni locali senza impostazioni locali per thread abilitato
In questo esempio il thread principale genera due thread figlio. Il primo thread, Thread A, abilita le impostazioni locali per thread chiamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Il secondo thread, Thread B e il thread principale, non abilitano le impostazioni locali per thread. Il thread B procede quindi per modificare le impostazioni locali usando la funzione setlocale della libreria di runtime C.
Poiché le impostazioni locali per thread B non sono abilitate per thread, le funzioni della libreria di runtime C nel thread B e nel thread principale iniziano a usare le impostazioni locali "francese". Le funzioni della libreria di runtime C nel thread A continuano a usare le impostazioni locali "C" perché thread A ha le impostazioni locali per thread abilitate. Inoltre, poiché setlocale non influisce sulle impostazioni locali della libreria standard C++, tutti gli oggetti della libreria standard C++ continuano a usare le impostazioni locali "C".
// multithread_locale_3.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>
#define NUM_THREADS 2
using namespace std;
unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);
BOOL localeSet = FALSE;
BOOL configThreadLocaleCalled = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);
int main()
{
HANDLE threads[NUM_THREADS];
unsigned aID;
threads[0] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadA, NULL, 0, &aID);
unsigned bID;
threads[1] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadB, NULL, 0, &bID);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
printf_s("[Thread main] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread main] locale::global is set to \"%s\"\n",
locale().name().c_str());
CloseHandle(threads[0]);
CloseHandle(threads[1]);
CloseHandle(printMutex);
return 0;
}
unsigned __stdcall RunThreadA(void *params)
{
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
configThreadLocaleCalled = TRUE;
while (!localeSet)
Sleep(100);
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread A] Per-thread locale is enabled.\n");
printf_s("[Thread A] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
unsigned __stdcall RunThreadB(void *params)
{
while (!configThreadLocaleCalled)
Sleep(100);
setlocale(LC_ALL, "french");
localeSet = TRUE;
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
printf_s("[Thread B] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "French_France.1252"
[Thread B] locale::global is set to "C"
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "C"
[Thread A] locale::global is set to "C"
[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "French_France.1252"
[Thread main] locale::global is set to "C"
Esempio: Modificare le impostazioni locali globali senza impostazioni locali per thread abilitato
In questo esempio il thread principale genera due thread figlio. Il primo thread, Thread A, abilita le impostazioni locali per thread chiamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Il secondo thread, Thread B e il thread principale, non abilitano le impostazioni locali per thread. Il thread B procede quindi per modificare le impostazioni locali usando il metodo locale::global della libreria standard C++.
Poiché le impostazioni locali per thread B non sono abilitate per thread, le funzioni della libreria di runtime C nel thread B e nel thread principale iniziano a usare le impostazioni locali "francese". Le funzioni della libreria di runtime C nel thread A continuano a usare le impostazioni locali "C" perché thread A ha le impostazioni locali per thread abilitate. Tuttavia, poiché il metodo locale::global modifica le impostazioni locali "globalmente", tutti gli oggetti della libreria standard C++ in tutti i thread iniziano a usare le impostazioni locali "francese".
// multithread_locale_4.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>
#define NUM_THREADS 2
using namespace std;
unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);
BOOL localeSet = FALSE;
BOOL configThreadLocaleCalled = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);
int main()
{
HANDLE threads[NUM_THREADS];
unsigned aID;
threads[0] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadA, NULL, 0, &aID);
unsigned bID;
threads[1] = (HANDLE)_beginthreadex(
NULL, 0, RunThreadB, NULL, 0, &bID);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
printf_s("[Thread main] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread main] locale::global is set to \"%s\"\n",
locale().name().c_str());
CloseHandle(threads[0]);
CloseHandle(threads[1]);
CloseHandle(printMutex);
return 0;
}
unsigned __stdcall RunThreadA(void *params)
{
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
configThreadLocaleCalled = TRUE;
while (!localeSet)
Sleep(100);
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread A] Per-thread locale is enabled.\n");
printf_s("[Thread A] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
unsigned __stdcall RunThreadB(void *params)
{
while (!configThreadLocaleCalled)
Sleep(100);
locale::global(locale("french"));
localeSet = TRUE;
WaitForSingleObject(printMutex, INFINITE);
printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
printf_s("[Thread B] CRT locale is set to \"%s\"\n",
setlocale(LC_ALL, NULL));
printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
locale().name().c_str());
ReleaseMutex(printMutex);
return 1;
}
[Thread B] Per-thread locale is NOT enabled.
[Thread B] CRT locale is set to "French_France.1252"
[Thread B] locale::global is set to "French_France.1252"
[Thread A] Per-thread locale is enabled.
[Thread A] CRT locale is set to "C"
[Thread A] locale::global is set to "French_France.1252"
[Thread main] Per-thread locale is NOT enabled.
[Thread main] CRT locale is set to "French_France.1252"
[Thread main] locale::global is set to "French_France.1252"
Vedi anche
Supporto del multithreading per il codice precedente (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internazionalizzazione
impostazioni locali
<clocale>
<impostazioni locali>
Classe locale