Partilhar via


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çãoObservaçã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;
}
  
  
  
  

Consulte também

Referência

_beginthread, beginthreadex

_configthreadlocale

setlocale

Internacionalização

Localidade

<clocale>

<locale>

locale Class

Conceitos

Suporte a multithreading código antigo (Visual C++)