Multithreading und Gebietsschemas
Sowohl die C-Runtime-Bibliothek als auch die C++-Standardbibliothek bieten Unterstützung für das Ändern des Gebietsschemas Ihres Programms. In diesem Thema werden Probleme erläutert, die beim Verwenden der Gebietsschemafunktionalität beider Bibliotheken in einer Multithreadanwendung auftreten.
Hinweise
Mit der C-Runtime-Bibliothek können Sie Multithread-Anwendungen mithilfe der und _beginthreadex
der _beginthread
Funktionen erstellen. In diesem Thema werden nur Multithread-Anwendungen behandelt, die mit diesen Funktionen erstellt wurden. Weitere Informationen finden Sie unter _beginthread, _beginthreadex.
Verwenden Sie die Setlocale-Funktion , um das Gebietsschema mithilfe der C-Runtime-Bibliothek zu ändern. In früheren Versionen von Visual C++ würde diese Funktion das Gebietsschema immer in der gesamten Anwendung ändern. Es gibt jetzt Unterstützung für das Festlegen des Gebietsschemas pro Thread. Dazu wird die _configthreadlocale-Funktion verwendet. Um anzugeben, dass setlocale nur das Gebietsschema im aktuellen Thread ändern soll, rufen Sie diesen Thread auf _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Umgekehrt bewirkt der Aufruf _configthreadlocale(_DISABLE_PER_THREAD_LOCALE)
, dass dieser Thread das globale Gebietsschema verwendet, und jeder Aufruf zum Setlocale in diesem Thread ändert das Gebietsschema in allen Threads, die nicht explizit pro Threadgebietsschema aktiviert wurden.
Verwenden Sie die Gebietsschemaklasse, um das Gebietsschema mithilfe der C++-Laufzeitbibliothek zu ändern. Durch Aufrufen der Locale::global-Methode ändern Sie das Gebietsschema in jedem Thread, der nicht explizit pro Threadgebietsschema aktiviert wurde. Um das Gebietsschema in einem einzelnen Thread oder Teil einer Anwendung zu ändern, erstellen Sie einfach eine Instanz eines locale
Objekts in diesem Thread oder Teil des Codes.
Hinweis
Durch Aufrufen von "locale::global " wird das Gebietsschema sowohl für die C++-Standardbibliothek als auch für die C-Runtime-Bibliothek geändert. Das Aufrufen von setlocale ändert jedoch nur das Gebietsschema für die C-Runtime-Bibliothek. Die C++-Standardbibliothek ist nicht betroffen.
Die folgenden Beispiele zeigen, wie Sie die Setlocale-Funktion , die Gebietsschemaklasse und die _configthreadlocale-Funktion verwenden, um das Gebietsschema einer Anwendung in verschiedenen Szenarien zu ändern.
Beispiel: Ändern des Gebietsschemas mit aktivierter Gebietsschemas pro Thread
In diesem Beispiel werden mit dem Standard Thread zwei untergeordnete Threads spawnsiert. Der erste Thread, Thread A, ermöglicht das Gebietsschema pro Thread durch Aufrufen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Der zweite Thread, Thread B und der Standard Thread, aktivieren kein Gebietsschema pro Thread. Thread A setzt dann fort, das Gebietsschema mithilfe der Setlocale-Funktion der C-Runtime-Bibliothek zu ändern.
Da Thread A pro Threadgebietsschema aktiviert ist, verwenden nur die C-Runtime-Bibliotheksfunktionen in Thread A das Gebietsschema "französisch". Die C-Runtime-Bibliotheksfunktionen in Thread B und im Standard Thread verwenden weiterhin das Gebietsschema "C". Da setlocale das Gebietsschema der C++-Standardbibliothek nicht beeinflusst, verwenden alle C++-Standardbibliotheksobjekte weiterhin das Gebietsschema "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"
Beispiel: Ändern des globalen Gebietsschemas mit aktivierter Gebietsschemas pro Thread
In diesem Beispiel werden mit dem Standard Thread zwei untergeordnete Threads spawnsiert. Der erste Thread, Thread A, ermöglicht das Gebietsschema pro Thread durch Aufrufen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Der zweite Thread, Thread B und der Standard Thread, aktivieren kein Gebietsschema pro Thread. Thread A setzt dann fort, das Gebietsschema mithilfe der locale::global-Methode der C++-Standardbibliothek zu ändern.
Da Thread A pro Threadgebietsschema aktiviert ist, verwenden nur die C-Runtime-Bibliotheksfunktionen in Thread A das Gebietsschema "französisch". Die C-Runtime-Bibliotheksfunktionen in Thread B und im Standard Thread verwenden weiterhin das Gebietsschema "C". Da die locale::global-Methode jedoch das Gebietsschema "global" ändert, beginnen alle C++-Standardbibliotheksobjekte in allen Threads mit der Verwendung des Gebietsschemas "französisch".
// 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"
Beispiel: Ändern des Gebietsschemas ohne aktiviertes Gebietsschema pro Thread
In diesem Beispiel werden mit dem Standard Thread zwei untergeordnete Threads spawnsiert. Der erste Thread, Thread A, ermöglicht das Gebietsschema pro Thread durch Aufrufen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Der zweite Thread, Thread B und der Standard Thread, aktivieren kein Gebietsschema pro Thread. Thread B setzt dann fort, das Gebietsschema mithilfe der Setlocale-Funktion der C-Runtime-Bibliothek zu ändern.
Da Thread B nicht pro Threadgebietsschema aktiviert ist, beginnen die C-Runtime-Bibliotheksfunktionen in Thread B und im Standard Thread mit der Verwendung des Gebietsschemas "französisch". Die C-Runtime-Bibliotheksfunktionen in Thread A verwenden weiterhin das Gebietsschema "C", da Thread A pro Threadgebietsschema aktiviert ist. Da setlocale das Gebietsschema der C++-Standardbibliothek nicht beeinflusst, verwenden alle C++-Standardbibliotheksobjekte weiterhin das Gebietsschema "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"
Beispiel: Ändern des globalen Gebietsschemas ohne aktiviertes Gebietsschema pro Thread
In diesem Beispiel werden mit dem Standard Thread zwei untergeordnete Threads spawnsiert. Der erste Thread, Thread A, ermöglicht das Gebietsschema pro Thread durch Aufrufen _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. Der zweite Thread, Thread B und der Standard Thread, aktivieren kein Gebietsschema pro Thread. Thread B setzt dann fort, das Gebietsschema mithilfe der locale::global-Methode der C++-Standardbibliothek zu ändern.
Da Thread B nicht pro Threadgebietsschema aktiviert ist, beginnen die C-Runtime-Bibliotheksfunktionen in Thread B und im Standard Thread mit der Verwendung des Gebietsschemas "französisch". Die C-Runtime-Bibliotheksfunktionen in Thread A verwenden weiterhin das Gebietsschema "C", da Thread A pro Threadgebietsschema aktiviert ist. Da die locale::global-Methode jedoch das Gebietsschema "global" ändert, beginnen alle C++-Standardbibliotheksobjekte in allen Threads mit der Verwendung des Gebietsschemas "französisch".
// 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"
Siehe auch
Multithreadingunterstützung für älteren Code (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internationalisierung
Gebietsschema
<clocale>
<Gebietsschema>
locale-Klasse