Wielowątkowość i ustawień regionalnych
Standardowa biblioteka języka C++ i biblioteka C Runtime zapewniają obsługę zmieniania ustawień regionalnych programu.W tym temacie omówiono problemy, które powstają, gdy za pomocą funkcji ustawień regionalnych, bibliotek, zarówno w aplikacji wielowątkowych.
Uwagi
Biblioteka C Runtime Library można tworzyć aplikacje wielowątkowe za pomocą _beginthread i _beginthreadex funkcji.W tym temacie omówiono tylko aplikacje wielowątkowe utworzone za pomocą tych funkcji.Aby uzyskać więcej informacji, zobacz _beginthread, _beginthreadex.
Aby zmienić ustawienia regionalne, przy użyciu biblioteki C Runtime, użyj setLocale funkcji.W poprzednich wersjach Visual C++, ta funkcja zawsze zmodyfikuje ustawienia regionalne całej całej aplikacji.Istnieje teraz obsługę ustawienia regionalne na podstawie dla wątku.Można to zrobić za pomocą _configthreadlocale funkcji.Aby określić, że setLocale należy zmieniać tylko ustawienia regionalne w bieżącym wątku, wywołanie _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) w tym wątku.Odwrotnie, wywołanie _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) spowoduje, że wątek do użytku globalnego ustawienia regionalne, a każde wywołanie setLocale w tym wątku będzie zmiana ustawień regionalnych w wszystkie wątki, które nie zostały jawnie włączone ustawienia regionalne dla wątku.
Aby zmienić ustawienia regionalne, przy użyciu biblioteki wykonawczej języka C++, użyj locale Class.Wywołując locale::global metodę, zmień ustawienia regionalne w każdym wątku, który nie został jawnie włączone ustawienia regionalne dla wątku.Aby zmienić ustawienia regionalne w pojedynczym wątku lub część aplikacji, po prostu utworzyć wystąpienia locale obiektu w tym wątku lub fragment kodu.
[!UWAGA]
Wywołanie locale::global zmienia ustawienia regionalne dla standardowa biblioteka języka C++ i biblioteka C Runtime Library.Jednakże wywoływania setLocale zmienia ustawienia regionalne tylko dla biblioteki C Runtime; Standardowa biblioteka języka C++ nie występuje.
Następujące przykłady przedstawiają metody korzystania setLocale funkcji, locale Classi _configthreadlocale funkcji, aby zmienić ustawienia regionalne wniosku w przypadku różnych scenariuszy.
Przykład
W tym przykładzie główny wątek uruchamia dwóch wątków podrzędnych.Pierwszy wątek wątek A, włącza ustawienia regionalne dla wątku, wywołując _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).Drugi wątek wątek B, jak również głównym wątku, nie należy włączać ustawień regionalnych dla wątku.Wątek, następnie przechodzi do zmiany ustawień regionalnych za pomocą setLocale funkcji biblioteki C Runtime.
Ponieważ wątek, A ustawienia regionalne dla wątku włączone, tylko funkcji C Runtime Library w wątku start, przy użyciu ustawień "Francuski".Funkcje C Runtime Library w wątku b oraz w głównym wątku nadal używać ustawień regionalnych "C".Ponadto od setLocale nie wpływa na ustawienia regionalne standardowa biblioteka języka C++, wszystkie standardowa biblioteka języka C++, obiekty nadal korzystać z ustawień regionalnych "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;
}
W tym przykładzie główny wątek uruchamia dwóch wątków podrzędnych.Pierwszy wątek wątek A, włącza ustawienia regionalne dla wątku, wywołując _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).Drugi wątek wątek B, jak również głównym wątku, nie należy włączać ustawień regionalnych dla wątku.Wątek, następnie przechodzi do zmiany ustawień regionalnych za pomocą locale::global metoda standardowa biblioteka języka C++.
Ponieważ wątek, A ustawienia regionalne dla wątku włączone, tylko funkcji C Runtime Library w wątku start, przy użyciu ustawień "Francuski".Funkcje C Runtime Library w wątku b oraz w głównym wątku nadal używać ustawień regionalnych "C".Ponieważ jednak locale::global metoda "globalnie" zmienia ustawienia regionalne, wszystkie obiekty standardowa biblioteka języka C++ wszystkie wątki rozpocząć korzystanie z locale "Francuski".
// 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;
}
W tym przykładzie główny wątek uruchamia dwóch wątków podrzędnych.Pierwszy wątek wątek A, włącza ustawienia regionalne dla wątku, wywołując _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).Drugi wątek wątek B, jak również głównym wątku, nie należy włączać ustawień regionalnych dla wątku.Wątek B, a następnie przechodzi do zmiany ustawień regionalnych za pomocą setLocale funkcji biblioteki C Runtime.
Ponieważ wątek b nie ma ustawień regionalnych dla wątku włączony, funkcje C Runtime Library w wątku b oraz w głównym wątku rozpocząć korzystanie z locale "Francuski".Funkcje C Runtime Library w wątku A Kontynuuj, aby użyć ustawień regionalnych "C", ponieważ wątek a ma ustawienia regionalne dla wątku włączone.Ponadto od setLocale nie wpływa na ustawienia regionalne standardowa biblioteka języka C++, wszystkie standardowa biblioteka języka C++, obiekty nadal korzystać z ustawień regionalnych "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;
}
W tym przykładzie główny wątek uruchamia dwóch wątków podrzędnych.Pierwszy wątek wątek A, włącza ustawienia regionalne dla wątku, wywołując _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).Drugi wątek wątek B, jak również głównym wątku, nie należy włączać ustawień regionalnych dla wątku.Wątek B, a następnie przechodzi do zmiany ustawień regionalnych za pomocą locale::global metoda standardowa biblioteka języka C++.
Ponieważ wątek b nie ma ustawień regionalnych dla wątku włączony, funkcje C Runtime Library w wątku b oraz w głównym wątku rozpocząć korzystanie z locale "Francuski".Funkcje C Runtime Library w wątku A Kontynuuj, aby użyć ustawień regionalnych "C", ponieważ wątek a ma ustawienia regionalne dla wątku włączone.Ponieważ jednak locale::global metoda "globalnie" zmienia ustawienia regionalne, wszystkie obiekty standardowa biblioteka języka C++ wszystkie wątki rozpocząć korzystanie z locale "Francuski".
// 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;
}