Multithread e localidades
A Biblioteca de Runtime de C e a Biblioteca padrão de C++ dão suporte para alterar a localidade do programa. Este tópico aborda os problemas que surgem ao usar a funcionalidade de localidade de ambas as bibliotecas em um aplicativo com multithread.
Comentários
Com a Biblioteca de Runtime de C, você pode criar aplicativos multithread usando as funções _beginthread
e _beginthreadex
. Este tópico aborda apenas aplicativos multithread criados usando essas funções. Para obter mais informações, consulte _beginthread, _beginthreadex.
Para alterar a localidade usando a Biblioteca de Runtime de C, use a função setlocale. Nas versões anteriores do Visual C++, essa função sempre modificava a localidade em todo o aplicativo. Agora há suporte para definir a localidade por thread. Isso é feito usando a função _configthreadlocale. Para especificar que setlocale só deve alterar a localidade no thread atual, chame _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
nesse thread. Por outro lado, a chamada _configthreadlocale(_DISABLE_PER_THREAD_LOCALE)
fará com que esse thread use a localidade global, e qualquer chamada para setlocale nesse thread alterará a localidade em todos os threads que não habilitaram explicitamente a localidade por thread.
Para alterar a localidade usando a Biblioteca de Runtime de C++, use a classe locale. Ao chamar o método locale::global, você altera a localidade em cada thread que não habilitou explicitamente a localidade por thread. Para alterar a localidade em um único thread ou parte de um aplicativo, basta criar uma instância de um objeto locale
nesse thread ou parte do código.
Observação
Chamar locale::global altera a localidade para a Biblioteca padrão de C++ e a Biblioteca de Runtime de C. No entanto, chamar setlocale altera apenas a localidade da Biblioteca de Runtime de C; a Biblioteca Padrão de C++ não é afetada.
Os exemplos a seguir mostram como usar a função setlocale, a classe locale e a função _configthreadlocale para alterar a localidade de um aplicativo em vários cenários diferentes.
Exemplo: alterar a localidade com a localidade por thread habilitada
Neste exemplo, o thread principal gera dois threads filho. O primeiro thread, Thread A, habilita a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. O segundo thread, Thread B, bem como o thread principal, não habilita a localidade por thread. Em seguida, o Thread A continua a alterar a localidade usando a função setlocale da Biblioteca de Runtime de C.
Como o Thread A tem a localidade por thread habilitada, somente as funções da Biblioteca de Runtime de C no Thread A começam a usar a localidade "french". As funções da Biblioteca de Runtime de C no Thread B e no thread principal continuam a usar a localidade "C". Além disso, como setlocale não afeta a localidade da Biblioteca padrão de C++, todos os objetos da Biblioteca padrão de C++ 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;
}
[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"
Exemplo: alterar a localidade global com a localidade por thread habilitada
Neste exemplo, o thread principal gera dois threads filho. O primeiro thread, Thread A, habilita a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. O segundo thread, Thread B, bem como o thread principal, não habilita a localidade por thread. Em seguida, o Thread A continua a alterar a localidade usando o método locale::global da Biblioteca padrão de C++.
Como o Thread A tem a localidade por thread habilitada, somente as funções da Biblioteca de Runtime de C no Thread A começam a usar a localidade "french". As funções da Biblioteca de Runtime de C no Thread B e no thread principal continuam a usar a localidade "C". No entanto, como o método locale::global altera a localidade "globalmente", todos os objetos da Biblioteca padrão de C++ em todos os threads começam a usar a localidade "french".
// 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"
Exemplo: alterar a localidade sem a localidade por thread habilitada
Neste exemplo, o thread principal gera dois threads filho. O primeiro thread, Thread A, habilita a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. O segundo thread, Thread B, bem como o thread principal, não habilita a localidade por thread. Em seguida, o Thread B continua a alterar a localidade usando a função setlocale da Biblioteca de Runtime de C.
Como o Thread B não tem a localidade por thread habilitada, as funções da Biblioteca de Runtime de C no Thread B e no thread principal começam a usar a localidade "french". As funções da Biblioteca de Runtime de C no Thread A continuam a usar a localidade "C" porque o Thread A tem a localidade por thread habilitada. Além disso, como setlocale não afeta a localidade da Biblioteca padrão de C++, todos os objetos da Biblioteca padrão de C++ 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;
}
[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"
Exemplo: alterar a localidade global sem a localidade por thread habilitada
Neste exemplo, o thread principal gera dois threads filho. O primeiro thread, Thread A, habilita a localidade por thread chamando _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
. O segundo thread, Thread B, bem como o thread principal, não habilita a localidade por thread. Em seguida, o Thread B continua a alterar a localidade usando o método locale::global da Biblioteca padrão de C++.
Como o Thread B não tem a localidade por thread habilitada, as funções da Biblioteca de Runtime de C no Thread B e no thread principal começam a usar a localidade "french". As funções da Biblioteca de Runtime de C no Thread A continuam a usar a localidade "C" porque o Thread A tem a localidade por thread habilitada. No entanto, como o método locale::global altera a localidade "globalmente", todos os objetos da Biblioteca padrão de C++ em todos os threads começam a usar a localidade "french".
// 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"
Confira também
Suporte de multithreading para código anterior (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internacionalização
Localidade
<clocale>
<locale>
Classe locale