Multithreading e localidades
Biblioteca C Runtime Library e a biblioteca C++ padrão oferecem suporte para alterar a localidade do seu programa.Este tópico aborda problemas que surgem ao usar a funcionalidade de localidade de ambas as bibliotecas em um aplicativo multithread.
Comentários
Com a biblioteca de tempo de execução C, você pode criar aplicativos multithread usando o _beginthread e _beginthreadex funções.Este tópico aborda somente aplicativos multithread criados usando essas funções.Para mais informações, consulte _beginthread, beginthreadex.
Para alterar a localidade usando a biblioteca de tempo de execução C, use o setlocale função.Em versões anteriores do Visual C++, essa função sempre seria modificar o local em todo o aplicativo.Há agora suporte para definir a localidade em uma base por thread.Isso é feito usando o _configthreadlocale função.Para especificar que setlocale só deve alterar a localidade do thread atual, chamada _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) no encadeamento.Por outro lado, chamando _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) fará com que esse thread para usar a localidade global e qualquer chamada para setlocale em que thread irá alterar a localidade de todos os segmentos que não tenha habilitado explicitamente localidade por thread.
Para alterar a localidade usando C++ Runtime Library, use o locale Class.Chamando o locale::global método, você alterar o local em cada thread que não tenha habilitado explicitamente localidade por thread.Para alterar a localidade em um único segmento ou parte de um aplicativo, basta criar uma instância de um locale esse segmento ou parte do código objeto.
Observação |
---|
Chamando locale::global altera a localidade para a biblioteca C++ padrão e a biblioteca C Runtime Library.No entanto, chamar setlocale apenas altera a localidade para a biblioteca C Runtime Library; a biblioteca C++ padrão não é afetada. |
Os exemplos a seguir mostram como usar o setlocale função, o locale Classe o _configthreadlocale função para alterar a localidade de um aplicativo em vários cenários diferentes.
Exemplo
Neste exemplo, o thread principal gera dois threads filho.O primeiro thread Thread A, permite que a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).O segundo segmento, o Thread B, bem como o thread principal, não habilite localidade por thread.Segmento de um, em seguida, prossegue para alterar a localidade usando o setlocale função de biblioteca C Runtime Library.
Desde que A Thread tem localidade por thread ativado, somente as funções de biblioteca C Runtime Library no segmento um início usando a localidade "francês".As funções de biblioteca C Runtime Library no segmento b e no thread principal continuam a usar a localidade "C".Além disso, desde setlocale não afeta a localidade de biblioteca C++ padrão, todos os biblioteca C++ padrão objetos continuam a usar a localidade "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;
}
Neste exemplo, o thread principal gera dois threads filho.O primeiro thread Thread A, permite que a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).O segundo segmento, o Thread B, bem como o thread principal, não habilite localidade por thread.Segmento de um, em seguida, prossegue para alterar a localidade usando o locale::global método da biblioteca C++ padrão.
Desde que A Thread tem localidade por thread ativado, somente as funções de biblioteca C Runtime Library no segmento um início usando a localidade "francês".As funções de biblioteca C Runtime Library no segmento b e no thread principal continuam a usar a localidade "C".No entanto, como o locale::global método altera a localidade "global", todos os objetos de biblioteca C++ padrão em todos os segmentos iniciar usando a localidade "francês".
// 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;
}
Neste exemplo, o thread principal gera dois threads filho.O primeiro thread Thread A, permite que a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).O segundo segmento, o Thread B, bem como o thread principal, não habilite localidade por thread.O thread b e prossegue para alterar a localidade usando o setlocale função de biblioteca C Runtime Library.
Como o Thread B não tem localidade por thread ativada, as funções de biblioteca C Runtime Library no segmento b e no thread principal iniciar usando a localidade "francês".As funções de biblioteca C Runtime Library continuar Thread A usar a localidade "C" porque o Thread A possui localidade por thread ativada.Além disso, desde setlocale não afeta a localidade de biblioteca C++ padrão, todos os biblioteca C++ padrão objetos continuam a usar a localidade "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;
}
Neste exemplo, o thread principal gera dois threads filho.O primeiro thread Thread A, permite que a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE).O segundo segmento, o Thread B, bem como o thread principal, não habilite localidade por thread.O thread b e prossegue para alterar a localidade usando o locale::global método da biblioteca C++ padrão.
Como o Thread B não tem localidade por thread ativada, as funções de biblioteca C Runtime Library no segmento b e no thread principal iniciar usando a localidade "francês".As funções de biblioteca C Runtime Library continuar Thread A usar a localidade "C" porque o Thread A possui localidade por thread ativada.No entanto, como o locale::global método altera a localidade "global", todos os objetos de biblioteca C++ padrão em todos os segmentos iniciar usando a localidade "francês".
// 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;
}