Multithreading e localidades

A biblioteca C Runtime Library e a biblioteca C++ padrão oferecem suporte para a alteração da localidade do seu programa. Este tópico discute os problemas que surgem ao usar a funcionalidade de localidade de ambas as bibliotecas em um aplicativo multithreaded.

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 os aplicativos multithread criados usando essas funções. For more information, see _beginthread, _beginthreadex.

Para alterar a localidade usando a biblioteca de tempo de execução C, use o setlocale função. Nas versões anteriores do Visual C++, essa função sempre modificaria a localidade em todo o aplicativo inteiro. Não há atualmente oferecem suporte a definição da 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) nesse segmento. 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 o thread irá alterar a localidade de todos os threads que não explicitamente habilitado por thread localidade.

Para alterar a localidade usando o C++ Runtime Library, use o locale Class. Chamando o locale::global método, você alterar a localidade de todos os threads que permitiu não explicitamente por thread localidade. Para alterar a localidade em um único thread ou a parte de um aplicativo, basta criar uma instância de um locale o objeto na thread ou parte do código.

ObservaçãoObservação

Chamando locale::global altera a localidade para a biblioteca C++ padrão e o 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 a função para alterar a localidade de um aplicativo em vários cenários diferentes.

Exemplo

Neste exemplo, o thread principal gera dois segmentos de filho. O primeiro thread, o 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 a função do C Runtime Library.

Desde que o Thread A possui uma localidade de cada thread habilitada, apenas o C Runtime Library funciona no Thread um início usando o "francês" localidade. As funções da C Runtime Library no segmento b e no thread principal continuam a usar o "C" localidade. Além disso, desde setlocale faz a localidade de biblioteca do afetam o C++ padrão, todos os objetos da biblioteca C++ padrão continuam a usar o "C" localidade.

// 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 segmentos de filho. O primeiro thread, o 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 o método do Standard C++ Library.

Desde que o Thread A possui uma localidade de cada thread habilitada, apenas o C Runtime Library funciona no Thread um início usando o "francês" localidade. As funções da C Runtime Library no segmento b e no thread principal continuam a usar o "C" localidade. No entanto, como o locale::global método altera a localidade "global", todos os objetos da biblioteca C++ padrão em todos os segmentos de começar a usar o "francês" localidade.

// 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 segmentos de filho. O primeiro thread, o 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, em seguida, prossegue para alterar a localidade usando o setlocale a função do C Runtime Library.

Como o Thread B não tem código de idioma por thread ativado, as funções da C Runtime Library no segmento b e no thread principal começar a usar o "francês" localidade. As funções da C Runtime Library no Thread um continuar a usar o "C" localidade porque o Thread A possui o código de idioma por thread ativado. Além disso, desde setlocale faz a localidade de biblioteca do afetam o C++ padrão, todos os objetos da biblioteca C++ padrão continuam a usar o "C" localidade.

// 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 segmentos de filho. O primeiro thread, o 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, em seguida, prossegue para alterar a localidade usando o locale::global o método do Standard C++ Library.

Como o Thread B não tem código de idioma por thread ativado, as funções da C Runtime Library no segmento b e no thread principal começar a usar o "francês" localidade. As funções da C Runtime Library no Thread um continuar a usar o "C" localidade porque o Thread A possui o código de idioma por thread ativado. No entanto, como o locale::global método altera a localidade "global", todos os objetos da biblioteca C++ padrão em todos os segmentos de começar a usar o "francês" localidade.

// 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

Internationalization

Locale

<clocale>

<locale>

locale Class

Conceitos

Multiencadeamento