Dela via


Flertråds- och localer

Både C Runtime-biblioteket och C++-standardbiblioteket har stöd för att ändra programmets nationella inställningar. I det här avsnittet beskrivs problem som uppstår när du använder lokaliseringsfunktionerna i båda biblioteken i ett flertrådat program.

Anmärkningar

Med C Runtime-biblioteket kan du skapa flertrådade program med hjälp av _beginthread funktionerna och _beginthreadex . Det här avsnittet beskriver endast flertrådade program som skapats med hjälp av dessa funktioner. Mer information finns i _beginthread, _beginthreadex.

Om du vill ändra nationella inställningar med hjälp av C Runtime-biblioteket använder du funktionen setlocale . I tidigare versioner av Visual C++skulle den här funktionen alltid ändra nationella inställningar i hela programmet. Det finns nu stöd för att ange nationella inställningar per tråd. Detta görs med hjälp av funktionen _configthreadlocale . Om du vill ange att setlocale endast ska ändra språkvarianten i den aktuella tråden anropar du _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) den tråden. Anrop _configthreadlocale(_DISABLE_PER_THREAD_LOCALE) gör att tråden använder det globala språket, och alla anrop till setlocale i den tråden ändrar språkvarianten i alla trådar som inte uttryckligen har aktiverat språkvarianten per tråd.

Om du vill ändra språkvarianten med hjälp av C++-körningsbiblioteket använder du språkklassen. Genom att anropa metoden locale::global ändrar du nationella inställningar i varje tråd som inte uttryckligen har aktiverat nationella inställningar per tråd. Om du vill ändra språkvarianten i en enda tråd eller del av ett program skapar du bara en instans av ett locale objekt i den tråden eller delen av koden.

Anmärkning

Anrop av locale::global ändrar lokal för både C++ Standardbiblioteket och C Runtime-biblioteket. Om du anropar setlocale ändras dock bara språkvarianten för C Runtime-biblioteket. C++-standardbiblioteket påverkas inte.

I följande exempel visas hur du använder funktionen setlocale , språkvariantklassen och funktionen _configthreadlocale för att ändra språkvarianten för ett program i flera olika scenarier.

Exempel: Ändra lokal inställning med per-trådslokalisering aktiverad

I det här exemplet skapar huvudtråden två underordnade trådar. Den första tråden, Tråd A, aktiverar lokalinställning per tråd genom att anropa _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Den andra tråden, Tråd B, samt huvudtråden, aktiverar inte nationella inställningar per tråd. Tråd A fortsätter sedan med att ändra nationella inställningar med hjälp av funktionen setlocale i C Runtime-biblioteket.

Eftersom tråd A har språkvarianten per tråd aktiverad börjar bara C Runtime Library-funktionerna i Tråd A med språkvarianten "franska". C Runtime-biblioteksfunktionerna i tråd B och i huvudtråden fortsätter att använda språkvarianten "C". Eftersom setlocale inte påverkar språkvarianten för C++-standardbiblioteket fortsätter alla C++ standardbiblioteksobjekt att använda språkvarianten "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"

Exempel: Ändra globala språkinställningar med språkinställning per tråd aktiverad.

I det här exemplet skapar huvudtråden två underordnade trådar. Den första tråden, Tråd A, aktiverar lokalinställning per tråd genom att anropa _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Den andra tråden, Tråd B, samt huvudtråden, aktiverar inte nationella inställningar per tråd. Tråd A fortsätter sedan med att ändra den lokala inställningen med hjälp av locale::global-metoden för C++-standardbiblioteket.

Eftersom tråd A har språkvarianten per tråd aktiverad börjar bara C Runtime Library-funktionerna i Tråd A med språkvarianten "franska". C Runtime-biblioteksfunktionerna i tråd B och i huvudtråden fortsätter att använda språkvarianten "C". Men eftersom metoden locale::global ändrar språkvarianten "globalt" börjar alla C++ Standard Library-objekt i alla trådar använda språkspråket "franska".

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

Exempel: Ändra nationella inställningar utan att språkvarianten per tråd har aktiverats

I det här exemplet skapar huvudtråden två underordnade trådar. Den första tråden, Tråd A, aktiverar lokalinställning per tråd genom att anropa _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Den andra tråden, Tråd B, samt huvudtråden, aktiverar inte nationella inställningar per tråd. Tråd B fortsätter sedan med att ändra nationella inställningar med hjälp av funktionen setlocale i C Runtime-biblioteket.

Eftersom tråd B inte har språkvarianten per tråd aktiverad fungerar C Runtime-biblioteket i tråd B och i huvudtråden börjar använda språkvarianten "franska". C Runtime-biblioteksfunktionerna i Tråd A fortsätter att använda språkvarianten "C" eftersom tråd A har språkvarianten per tråd aktiverad. Eftersom setlocale inte påverkar språkvarianten för C++-standardbiblioteket fortsätter alla C++ standardbiblioteksobjekt att använda språkvarianten "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"

Exempel: Ändra globala nationella inställningar utan att språkvarianten per tråd har aktiverats

I det här exemplet skapar huvudtråden två underordnade trådar. Den första tråden, Tråd A, aktiverar lokalinställning per tråd genom att anropa _configthreadlocale(_ENABLE_PER_THREAD_LOCALE). Den andra tråden, Tråd B, samt huvudtråden, aktiverar inte nationella inställningar per tråd. Tråd B fortsätter sedan med att ändra locale med hjälp av locale::global-metoden i C++-standardbiblioteket.

Eftersom tråd B inte har språkvarianten per tråd aktiverad fungerar C Runtime-biblioteket i tråd B och i huvudtråden börjar använda språkvarianten "franska". C Runtime-biblioteksfunktionerna i Tråd A fortsätter att använda språkvarianten "C" eftersom tråd A har språkvarianten per tråd aktiverad. Men eftersom metoden locale::global ändrar språkvarianten "globalt" börjar alla C++ Standard Library-objekt i alla trådar använda språkspråket "franska".

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

Se även

Stöd för multitrådning för äldre kod (Visual C++)
_beginthread, _beginthreadex
_configthreadlocale
setlocale
Internationalisering
regionala inställningar
<clocale>
<Locale>
lokal klass